고유하게 분리 된 픽셀


30

들어 N 에 의해 N 화상 더 이격 거리가 두 번 이상 존재하지 않도록 픽셀들의 세트를 찾는. 즉, 두 픽셀이 거리 d 로 분리 된 경우 정확히 d 로 분리 된 두 픽셀 ( 유클리드 거리 사용 )입니다. 참고 것을 D 필요 정수가 될 수 없습니다.

문제는 다른 사람보다 더 큰 세트를 찾는 것입니다.

사양

입력 할 필요가 없습니다.이 콘테스트의 N 은 619로 고정됩니다.

(사람들이 계속 묻고 있기 때문에 숫자 619에 대해서는 특별한 것이 없습니다. 최적의 솔루션을 만들 가능성이 거의 없으며, Stack Exchange가 자동으로 축소하지 않고 N x N 이미지를 표시 할 수있을 정도로 작도록 선택되었습니다. 최대 630 x 630의 전체 크기로 표시되었으며,이를 초과하지 않는 최대 소수를 사용하기로 결정했습니다.)

출력은 공백으로 구분 된 정수 목록입니다.

출력의 각 정수는 0부터 영어 읽기 순서로 번호가 매겨진 픽셀 중 하나를 나타냅니다. 예를 들어 N = 3의 경우 위치는 다음 순서로 번호가 지정됩니다.

0 1 2
3 4 5
6 7 8

원하는 경우 최종 스코어링 출력을 쉽게 사용할 수있는 한 진행 중에 진행 정보를 출력 할 수 있습니다. STDOUT 또는 파일 또는 아래 스택 스 니펫 심사에 붙여 넣기 가장 쉬운 방법으로 출력 할 수 있습니다.

N = 3

선택된 좌표 :

(0,0)
(1,0)
(2,1)

산출:

0 1 5

승리

점수는 출력의 위치 수입니다. 가장 높은 점수를 얻은 유효한 답변 중에서 해당 점수로 결과를 게시하는 것이 가장 빠릅니다.

코드가 결정적 일 필요는 없습니다. 최상의 결과를 게시 할 수 있습니다.


연구 관련 분야

( 골롬 링크에 대한 Abulafia 감사 합니다)

이것들 중 어느 것도이 문제와 동일하지는 않지만, 그것들은 개념 상 비슷하며 이것에 접근하는 방법에 대한 아이디어를 줄 수 있습니다 :

이 질문에 필요한 포인트는 Golomb 사각형과 동일한 요구 사항이 아닙니다. 골롬 (Golomb) 사각형은 각 점 의 벡터 가 서로 고유 해야하므로 1 차원 케이스에서 확장됩니다 . 이는 수평으로 2 거리만큼 분리 된 2 개의 점과 수직으로 2 거리만큼 분리 된 2 개의 점이있을 수 있음을 의미합니다.

이 질문의 경우 스칼라 거리가 고유해야하므로 2의 수평 및 수직 분리가 불가능합니다.이 질문에 대한 모든 솔루션은 Golomb 사각형이지만 모든 Golomb 사각형이 유효한 솔루션은 아닙니다. 이 질문.


상한

데니스 는 채팅 에서 487이 점수의 상한이며도움이 된다는 점을 도움으로 지적했습니다 .

내 CJam 코드 ( 619,2m*{2f#:+}%_&,) 에 따르면 0에서 618 사이의 두 정수의 제곱의 합계로 쓸 수있는 118800 개의 고유 번호가 있습니다 (둘 다 포함). n 픽셀은 서로 n (n-1) / 2 고유 거리를 요구합니다. n = 488의 경우 118828이됩니다.

따라서 이미지의 모든 잠재적 픽셀 사이에 118,800 개의 서로 다른 길이가있을 수 있으며, 488 개의 검은 픽셀을 배치하면 118,828 개의 길이가 발생하므로 모두 고유 할 수 없습니다.

누구든지 이것보다 낮은 상한의 증거가 있다면 듣고 싶습니다.


리더 보드

(각 사용자에 의한 최상의 답변)

leaderboard image


스택 스 니펫 판사


나는 여기에서 Piet 답변을보고
싶었다

@ C5H8NNaO4 경쟁은 끝이 없습니다-최적의 솔루션 근처에 아무도 없기 때문에 새로운 답변을위한 충분한 공간이 있습니다 ...
trichoplax

입증 된 상한 및 실험적 픽셀 목록 모두에 대해 바운티를 제공하고 있기 때문에이 문제에 어떤 종류의 응용이 있다고 가정합니다.
페이탈 라이즈

내가 알고있는 것은 타인의 마음을 사로 잡는 것이 아니라, 하나를 듣는 것에 매혹 될 것이다. 비슷한 문제 Costas 어레이 에는 실용적인 응용 프로그램이 나열되어 있지만이 특정 문제에 대해서는 아무것도 찾지 못했습니다.
trichoplax

1
나는 이것을보고 있었고, n = 487은 픽셀의 최소 상한이라고 생각합니다. 호기심에서 현상금의 상한선이 없다는 증거를 받아 들일 것입니까?
Mego

답변:


13

파이썬 3 135 136 137

10 6830 20470 47750 370770 148190 306910 373250 267230 354030 30390 361470 118430 58910 197790 348450 381336 21710 183530 305050 2430 1810 365832 99038 381324 39598 262270 365886 341662 15478 9822 365950 44526 58862 24142 381150 31662 237614 118830 380846 7182 113598 306750 11950 373774 111326 272358 64310 43990 200278 381014 165310 254454 12394 382534 87894 6142 750 382478 15982 298326 70142 186478 152126 367166 1162 23426 341074 7306 76210 140770 163410 211106 207962 35282 165266 300178 120106 336110 30958 158 362758 382894 308754 88434 336918 244502 43502 54990 279910 175966 234054 196910 287284 288468 119040 275084 321268 17968 2332 86064 340044 244604 262436 111188 291868 367695 362739 370781 375723 360261 377565 383109 328689 347879 2415 319421 55707 352897 313831 302079 19051 346775 361293 328481 35445 113997 108547 309243 19439 199037 216463 62273 174471 207197 167695 296927

각 단계에서 선택한 픽셀까지의 거리 집합이 다른 픽셀의 거리와 가장 겹치는 유효한 픽셀을 선택하는 탐욕스러운 알고리즘을 사용하여 발견되었습니다.

구체적으로 점수는

score(P) = sum(number of pixels with D in its distance set
               for each D in P's distance set)

가장 낮은 점수를 가진 픽셀이 선택됩니다.

포인트 10(예 :)로 검색이 시작됩니다 (0, 10). 이 부분은 조정 가능하므로 다른 픽셀로 시작하면 더 나은 결과를 얻을 수 있습니다.

상당히 느린 알고리즘이므로 최적화 / 휴리스틱을 추가하고 역 추적을 시도하고 있습니다. PyPy는 속도를 권장합니다.

에 테스트해야하는 알고리즘을 마련하려고 누군가가 N = 10,있는 나는 9있어 (그러나 이것은했다 많은 미세 조정 및 다른 초기 점을 노력을) :

enter image description here

암호

from collections import Counter, defaultdict
import sys
import time

N = 619

start_time = time.time()

def norm(p1, p2):
    return (p1//N - p2//N)**2 + (p1%N - p2%N)**2

selected = [10]
selected_dists = {norm(p1, p2) for p1 in selected for p2 in selected if p1 != p2}
pix2dist = {} # {candidate pixel: {distances to chosen}}
dist2pix = defaultdict(set)

for pixel in range(N*N):
    if pixel in selected:
        continue

    dist_list = [norm(pixel, p) for p in selected]
    dist_set = set(dist_list)

    if len(dist_set) != len(dist_list) or dist_set & selected_dists:
        continue

    pix2dist[pixel] = dist_set

    for dist in dist_set:
        dist2pix[dist].add(pixel)

while pix2dist:
    best_score = None
    best_pixel = None

    for pixel in sorted(pix2dist): # Sorting for determinism
        score = sum(len(dist2pix[d]) for d in pix2dist[pixel])

        if best_score is None or score < best_score:
            best_score = score
            best_pixel = pixel

    added_dists = pix2dist[best_pixel]
    selected_dists |= added_dists
    del pix2dist[best_pixel]
    selected.append(best_pixel)

    for d in added_dists:
        dist2pix[d].remove(best_pixel)

    to_remove = set()
    for pixel in pix2dist:
        new_dist = norm(pixel, best_pixel)

        if (new_dist in selected_dists or new_dist in pix2dist[pixel]
                or added_dists & pix2dist[pixel]):
            to_remove.add(pixel)
            continue

        pix2dist[pixel].add(new_dist)
        dist2pix[new_dist].add(pixel)

    for pixel in to_remove:
        for d in pix2dist[pixel]:
            dist2pix[d].remove(pixel)

        del pix2dist[pixel]

    print("Selected: {}, Remaining: {}, Chosen: ({}, {})".format(len(selected), len(pix2dist),
                                                                 best_pixel//N, best_pixel%N))
    sys.stdout.flush()

print(*selected)
print("Time taken:", time.time() - start_time)

3
나는 무차별 강제 N=10로 9 점을 가진 많은 독특한 레이아웃이 있지만 그것은 당신이 할 수있는 최선입니다.

5

SWI- 프롤로그, 점수 131

초기 답변보다 거의 낫지는 않지만 이것이 조금 더 시작될 것이라고 생각합니다. 이 알고리즘은 왼쪽 상단 픽셀 (픽셀 0), 오른쪽 하단 픽셀 (픽셀 383160), 픽셀 1, 픽셀 383159로 시작하여 대체 방법으로 픽셀을 시도한다는 점을 제외하고는 Python 답변과 동일합니다. 등

a(Z) :-
    N = 619,
    build_list(N,Z).

build_list(N,R) :-
    M is N*N,
    get_list([M,-1],[],L),
    reverse(L,O),
    build_list(N,O,[],[],R).

get_list([A,B|C],R,Z) :-
    X is A - 1,
    Y is B + 1,
    (X =< Y,
    Z = R
    ;
    get_list([X,Y,A,B|C],[X,Y|R],Z)).

build_list(_,[],R,_,R) :- !.
build_list(N,[A|T],R,W,Z) :-
    separated_pixel(N,A,R,W,S),
    is_set(S),
    flatten([W|S],V),!,
    build_list(N,T,[A|R],V,Z)
    ;build_list(N,T,R,W,Z).


separated_pixel(N,A,L,W,R) :-
    separated_pixel(N,A,L,[],W,R).

separated_pixel(N,A,[A|T],R,W,S) :-
        separated_pixel(N,A,T,R,W,S).

separated_pixel(N,A,[B|T],R,W,S) :-
    X is (A mod N - B mod N)*(A mod N - B mod N),
    Y is (A//N - B//N)*(A//N - B//N),
    Z is X + Y,
    \+member(Z,W),
    separated_pixel(N,A,T,[Z|R],W,S).

separated_pixel(_,_,[],R,_,R).

입력:

a(A).

산출:

Z = [202089, 180052, 170398, 166825, 235399, 138306, 126354, 261759, 119490, 117393, 281623, 95521, 290446, 299681, 304310, 78491, 314776, 63618, 321423, 60433, 323679, 52092, 331836, 335753, 46989, 40402, 343753, 345805, 36352, 350309, 32701, 32470, 352329, 30256, 28089, 357859, 23290, 360097, 22534, 362132, 20985, 364217, 365098, 17311, 365995, 15965, 15156, 368487, 370980, 371251, 11713, 372078, 372337, 10316, 373699, 8893, 374417, 8313, 7849, 7586, 7289, 6922, 376588, 6121, 5831, 377399, 377639, 4941, 378494, 4490, 379179, 3848, 379453, 3521, 3420, 379963, 380033, 3017, 380409, 2579, 380636, 2450, 2221, 2006, 381235, 1875, 381369, 381442, 381682, 1422, 381784, 1268, 381918, 1087, 382144, 382260, 833, 382399, 697, 382520, 622, 382584, 382647, 382772, 384, 382806, 319, 286, 382915, 382939, 190, 172, 383005, 128, 383050, 93, 383076, 68, 383099, 52, 40, 383131, 21, 383145, 10, 383153, 4, 383158, 1, 383160, 0]

스택 스 니펫의 이미지

131 points


이론적으로 최대 값 인 487이 있기 때문에, 점진적인 증가도 중요합니다 ...
trichoplax

표시된대로 출력이 스택 스 니펫에서 작동 했습니까? 필자는 예제 응답에서와 같이 분리 된 공간을 지정했지만 그 주된 이유는 스택 스 니펫이 작동하기 때문입니다.
trichoplax

@trichoplax 그래, 오타 야. 픽셀 0부터 시작해서 고칠 게. 이미지를 얻으려면 두 대괄호 사이의 출력 부분을 선택하고 쉼표를 모두 제거했습니다. 그러나 스택 스 니펫은 쉼표로 구분 된 픽셀에서 작동하는 것 같습니다.
페이탈 라이즈

4

Haskell- 115 130 131 135 136

저는 영감을받은 에라토스테네스의 체, 특히 에라토스테네스 의 진짜 체 , 하비 머드 칼리지의 Melissa E. O'Neill의 논문입니다. 내 원래 버전 (인덱스 순서로 포인트를 고려한)은 매우 빨리 포인트를 체질 했습니다. 어떤 이유로 나는이 버전에서 포인트를 "체질"하기 전에 포인트를 셔플하기로 결정했습니다 (단지 사용하여 다른 답변을 쉽게 생성 할 수 있다고 생각합니다) 무작위 생성기의 새로운 시드). 포인트는 더 이상 어떤 종류의 순서도 없기 때문에 더 이상 체질이 더 이상 진행되지 않으므로 결과적으로 단일 115 포인트 응답을 생성하는 데 몇 분이 걸립니다. 녹아웃 Vector이 아마도 더 나은 선택 일 것입니다.

따라서이 버전을 검사 점으로 사용하면 "Genuine Sieve"알고리즘으로 돌아가서 List 모나드를 활용하거나에 Set대한 해당 작업을 교체하는 두 가지 분기 가 Vector있습니다.

편집 : 따라서 작업 버전 2의 경우 체 알고리즘으로 되돌아 가서 "복수"생성을 개선했습니다 (소수점 생성과 유사하게 두 점 사이의 거리와 같은 반경을 가진 원의 정수 좌표에서 점을 찾아서 인덱스를 두드립니다) ) 및 불필요한 재 계산을 피함으로써 일정한 시간 개선 효과를 제공합니다.

어떤 이유로 프로파일 링을 켠 상태에서 다시 컴파일 할 수 없지만 현재 주요 병목 현상은 역 추적이라고 생각합니다. 약간의 병렬 처리와 동시성을 탐색하면 선형 속도가 향상되지만 메모리 소진으로 인해 2 배 향상 될 수 있습니다.

편집 : 버전 3은 약간의 구불 구불 한 것으로, 먼저 다음 𝐧 지수 (이전 선택에서 체질 한 후)를 가져 와서 다음 최소 녹아웃 세트를 생성 한 지수를 선택하는 휴리스틱을 실험했습니다. 이것은 너무 느리게 끝나서 전체 검색 공간 무차별 대입법으로 돌아갔습니다. 원점에서 거리를 기준으로 점을 정렬하는 아이디어가 나에게 왔으며 (내 인내심이 지속되는 시점에) 하나의 점으로 개선되었습니다. 이 버전은 인덱스 0을 원점으로 선택하므로 평면의 중심점을 시도해 볼 가치가 있습니다.

편집 : 검색 공간을 재정렬하여 중심에서 가장 먼 지점을 우선 순위로 지정하여 4 점을 선택했습니다. 당신이 내 코드를 테스트하는 경우, (135) (136)는 실제로 두 번째 세 번째 솔루션은 발견했다. 빠른 편집 : 이 버전은 계속 실행하면 생산성을 유지할 가능성이 가장 높습니다. 나는 137에 묶은 다음 138을 기다리는 인내심이 부족한 것 같습니다.

나는 (그 사람에게 도움이 될 수 있음)주의 한가지는 당신이 (즉, 제거 평면의 중심에서 포인트 순서를 설정 한 경우 (d*d -)에서 originDistance) 이미지 형성 외모 스파 스 프라임 나선형 같은 비트.

{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE BangPatterns #-}

module Main where

import Data.Function (on)
import Data.List     (tails, sortBy)
import Data.Maybe    (fromJust)
import Data.Ratio
import Data.Set      (fromList, toList, union, difference, member)

import System.IO

sideLength :: Int
sideLength = 619

data Point = Point {  x :: !Int,  y :: !Int } deriving (Ord, Eq)
data Delta = Delta { da :: !Int, db :: !Int }

euclidean :: Delta -> Int
euclidean Delta{..} = da*da + db*db

instance Eq Delta where
  (==) = (==) `on` euclidean

instance Ord Delta where
  compare = compare `on` euclidean

delta :: Point -> Point -> Delta
delta a b = Delta (min dx dy) (max dx dy)
  where
    dx = abs (x a - x b)
    dy = abs (y a - y b)

equidistant :: Dimension -> Point -> Point -> [Point]
equidistant d a b =
  let
    (dx, dy) = (x a - x b, y a - y b)
    m = if dx == 0 then Nothing else Just (dy % dx)                    -- Slope
    w = if dy == 0 then Nothing else Just $ maybe 0 (negate . recip) m -- Negative reciprocal
    justW = fromJust w -- Moral bankruptcy
    (px, py) = ((x a + x b) % 2, (y a + y b) % 2)                      -- Midpoint
    b0 = py - (justW * px)                                             -- Y-intercept
    f q = justW * q + b0                                               -- Perpendicular bisector
  in
   maybe (if denominator px == 1 then map (Point (numerator px)) [0..d - 1] else [])
         ( map (\q -> Point q (numerator . f . fromIntegral $ q))
         . filter ((== 1) . denominator . f . fromIntegral)
         )
         (w >> return [0..d - 1])

circle :: Dimension -> Point -> Delta -> [Point]
circle d p delta' =
  let
    square = (^(2 :: Int))
    hypoteneuse = euclidean delta'
    candidates = takeWhile ((<= hypoteneuse) . square) [0..d - 1]
    candidatesSet = fromList $ map square [0..d - 1]
    legs = filter ((`member` candidatesSet) . (hypoteneuse -) . square) candidates
    pythagoreans = zipWith Delta legs
                 $ map (\l -> floor . sqrt . (fromIntegral :: Int -> Double) $ hypoteneuse - square l) legs
  in
    toList . fromList $ concatMap (knight p) pythagoreans

knight :: Point -> Delta -> [Point]
knight Point{..} Delta{..} =
    [ Point (x + da) (y - db), Point (x + da) (y + db)
    , Point (x + db) (y - da), Point (x + db) (y + da)
    , Point (x - da) (y - db), Point (x - da) (y + db)
    , Point (x - db) (y - da), Point (x - db) (y + da)
    ]

type Dimension = Int
type Index = Int

index :: Dimension -> Point -> Index
index d Point{..} = y * d + x

point :: Dimension -> Index -> Point
point d i = Point (i `rem` d) (i `div` d)

valid :: Dimension -> Point -> Bool
valid d Point{..} = 0 <= x && x < d
                 && 0 <= y && y < d

isLT :: Ordering -> Bool
isLT LT = True
isLT _  = False

sieve :: Dimension -> [[Point]]
sieve d = [i0 : sieve' is0 [i0] [] | (i0:is0) <- tails . sortBy originDistance . map (point d) $ [0..d*d - 1]]
  where
    originDistance :: Point -> Point -> Ordering
    originDistance = compare `on` ((d*d -) . euclidean . delta (point d (d*d `div` 2)))

    sieve' :: [Point] -> [Point] -> [Delta] -> [Point]
    sieve' []     _  _ = []
    sieve' (i:is) ps ds = i : sieve' is' (i:ps) ds'
      where
        ds' = map (delta i) ps ++ ds
        knockouts = fromList [k | d' <- ds
                                , k  <- circle d i d'
                                , valid d k
                                , not . isLT $ k `originDistance` i
                                ]
            `union` fromList [k | q  <- i : ps
                                , d' <- map (delta i) ps
                                , k  <- circle d q d'
                                , valid d k
                                , not . isLT $ k `originDistance` i
                                ]
            `union` fromList [e | q <- ps
                                , e <- equidistant d i q
                                , valid d e
                                , not . isLT $ e `originDistance` i
                                ]
        is' = sortBy originDistance . toList $ fromList is `difference` knockouts

main :: IO ()
main = do let answers = strictlyIncreasingLength . map (map (index sideLength)) $ sieve sideLength
          hSetBuffering stdout LineBuffering
          mapM_ (putStrLn . unwords . map show) $ answers
  where
    strictlyIncreasingLength :: [[a]] -> [[a]]
    strictlyIncreasingLength = go 0
      where
        go _ []     = []
        go n (x:xs) = if n < length x then x : go (length x) xs else go n xs

산출

1237 381923 382543 382541 1238 1857 380066 5 380687 378828 611 5571 382553 377587 375113 3705 8664 376356 602 1253 381942 370161 12376 15475 7413 383131 367691 380092 376373 362114 36 4921 368291 19180 382503 26617 3052 359029 353451 29716 382596 372674 352203 8091 25395 12959 382479 381987 35894 346031 1166 371346 336118 48276 2555 332400 46433 29675 380597 13066 382019 1138 339859 368230 29142 58174 315070 326847 56345 337940 2590 382663 320627 70553 19278 7309 82942 84804 64399 5707 461 286598 363864 292161 89126 371267 377122 270502 109556 263694 43864 382957 824 303886 248218 18417 347372 282290 144227 354820 382909 380301 382808 334361 375341 2197 260623 222212 196214 231526 177637 29884 251280 366739 39442 143568 132420 334718 160894 353132 78125 306866 140600 297272 54150 240054 98840 219257 189278 94968 226987 265881 180959 142006 218763 214475

인상적인 개선. 현상금이 할당되기 전에 138까지 2 시간 남았습니다. 어느 쪽이든 잘 작동합니다 ...
trichoplax

그 목표를 달성 할 것 같지 않지만 여전히 137 요소 세트를 생성하지 못했습니다. 이 방법은 아마도 도청 된 것 같습니다 ...
RB

다른 접근 방식을 가진 두 가지 답변이 같은 크기로 최대에 도달한다는 사실에 흥미가 있습니다.
trichoplax

나는 상한이 아마도 상당히 가깝다고 생각합니다. 무한 평면과 두 점을 고려하십시오. 거리에 상관없이 해당 점을 최적으로 배치 하면 선택한 두 점의 중심으로 d반경의 원을 추적하여 고려에서 제외되는 다른 점의 수를 최소화합니다 d. 둘레는 세 개의 다른 정수 좌표 (90, 180 및 270도 회전)에만 닿습니다. 원), 정수 좌표가없는 수직 이등분 선. 따라서 각 새로운 포인트 n+16n다른 포인트를 고려에서 제외합니다 (최적의 선택).
RB

3

파이썬 3, 129 점

이것은 일을 시작하기위한 예의 대답입니다.

순진한 접근 방식으로 픽셀을 순서대로 진행하고 픽셀이 다 떨어질 때까지 중복 거리를 두지 않는 첫 번째 픽셀을 선택하십시오.

암호

width = 619
height = 619
area = width * height
currentAttempt = 0

temporaryLengths = []
lengths = []
points = []
pixels = []
for i in range(area):
    pixels.append(0)


def generate_points():
    global lengths
    while True:
        candidate = vacantPixel()
        if isUnique(candidate):
            lengths += temporaryLengths
            pixels[candidate] = 1
            points.append(candidate)
            print(candidate)
        if currentAttempt == area:
            break
    filename = 'uniquely-separated-points.txt'
    with open(filename, 'w') as file:
        file.write(' '.join(points))


def isUnique(n):
    x = n % width
    y = int(n / width)
    temporaryLengths[:] = []
    for i in range(len(points)):
        point = points[i]
        a = point % width
        b = int(point / width)
        d = distance(x, y, a, b)
        if d in lengths or d in temporaryLengths: 
            return False
        temporaryLengths.append(d)
    return True


def distance(x1, y1, x2, y2):
    xd = x2 - x1
    yd = y2 - y1
    return (xd*xd + yd*yd) ** 0.5


def vacantPixel():
    global currentAttempt
    while True:
        n = currentAttempt
        currentAttempt += 1
        if pixels[n] == 0:
            break
    return n


generate_points()

산출

0 1 3 7 12 20 30 44 65 80 96 122 147 181 203 251 289 360 400 474 564 592 627 660 747 890 1002 1155 1289 1417 1701 1789 1895 2101 2162 2560 2609 3085 3121 3331 3607 4009 4084 4242 4495 5374 5695 6424 6762 6808 7250 8026 8356 9001 9694 10098 11625 12881 13730 14778 15321 16091 16498 18507 19744 20163 20895 23179 25336 27397 31366 32512 33415 33949 39242 41075 46730 47394 48377 59911 61256 66285 69786 73684 79197 89530 95447 102317 107717 111751 116167 123198 126807 130541 149163 149885 154285 159655 163397 173667 173872 176305 189079 195987 206740 209329 214653 220911 230561 240814 249310 269071 274262 276855 285295 305962 306385 306515 312310 314505 324368 328071 348061 350671 351971 354092 361387 369933 376153

스택 스 니펫의 이미지

image of 129 uniquely separated pixels


3

파이썬 3, 130

비교를 위해 다음은 재귀 역 추적기 구현입니다.

N = 619

def norm(p1, p2):
    return (p1//N - p2//N)**2 + (p1%N - p2%N)**2

def solve(selected, dists):
    global best

    if len(selected) > best:
        print(len(selected), "|", *selected)
        best = len(selected)

    for pixel in (range(selected[-1]+1, N*N) if selected else range((N+1)//2+1)):
        # By symmetry, place first pixel in first half of top row
        added_dists = [norm(pixel, p) for p in selected]
        added_set = set(added_dists)

        if len(added_set) != len(added_dists) or added_set & dists:
            continue

        selected.append(pixel)
        dists |= added_set

        solve(selected, dists)

        selected.pop()
        dists -= added_set

print("N =", N)
best = 0
selected = []
dists = set()
solve(selected, dists)

질식을 시작하기 전에 다음 130 픽셀 솔루션을 빠르게 찾습니다.

0 1 3 7 12 20 30 44 65 80 96 122 147 181 203 251 289 360 400 474 564 592 627 660 747 890 1002 1155 1289 1417 1701 1789 1895 2101 2162 2560 2609 3085 3121 3331 3607 4009 4084 4242 4495 5374 5695 6424 6762 6808 7250 8026 8356 9001 9694 10098 11625 12881 13730 14778 15321 16091 16498 18507 19744 20163 20895 23179 25336 27397 31366 32512 33415 33949 39242 41075 46730 47394 48377 59911 61256 66285 69786 73684 79197 89530 95447 102317 107717 111751 116167 123198 126807 130541 149163 149885 154285 159655 163397 173667 173872 176305 189079 195987 206740 209329 214653 220911 230561 240814 249310 269071 274262 276855 285295 305962 306385 306515 312310 314505 324368 328071 348061 350671 351971 354092 361387 371800 376153 378169

더 중요한 것은 작은 사례에 대한 솔루션을 확인하는 데 사용하고 있습니다. 의 경우 N <= 8최적은 다음과 같습니다.

1: 1 (0)
2: 2 (0 1)
3: 3 (0 1 5)
4: 4 (0 1 6 12)
5: 5 (0 1 4 11 23)
6: 6 (0 1 9 23 32 35)
7: 7 (0 2 9 20 21 40 48)
8: 7 (0 1 3 12 22 56 61)
9: 8 (0 1 3 8 15 37 62 77)
10: 9 (0 1 7 12 30 53 69 80 89)

첫 번째 사전 편찬 법은 괄호 안에 표시되어 있습니다.

미확인 :

11: 10 (0 2 3 7 21 59 66 95 107 120)
12: 10 (0 1 3 7 33 44 78 121 130 140)

3

스칼라, 132

순진한 솔루션처럼 왼쪽에서 오른쪽으로, 위에서 아래로 스캔하지만 다른 픽셀 위치에서 시작하려고합니다.

import math.pow
import math.sqrt

val height, width = 619
val area = height * width

case class Point(x: Int, y: Int)

def generate(n: Int): Set[Point] = {

  def distance(p: Point, q: Point) = {
    def square(x: Int) = x * x
    sqrt(square(q.x - p.x) + square(q.y - p.y))
  }

  def hasDuplicates(s: Seq[_]) = s.toSet.size != s.size

  def rotate(s: Vector[Point]): Vector[Point] = s.drop(n) ++ s.take(n)

  val remaining: Vector[Point] =
    rotate((for (y <- 0 until height; x <- 0 until width) yield { Point(x, y) }).toVector)
  var unique = Set.empty[Point]
  var distances = Set.empty[Double]
  for (candidate <- remaining) {
    if (!unique.exists(p => distances.contains(distance(candidate, p)))) {
      val candidateDistances = unique.toSeq.map(p => distance(candidate, p))
      if (!hasDuplicates(candidateDistances)) {
        unique = unique + candidate
        distances = distances ++ candidateDistances
      }
    }
  }
  unique
}

def print(s: Set[Point]) = {
  def toRowMajor(p: Point) = p.y*height + p.x
  println(bestPixels.map(toRowMajor).toSeq.sorted.mkString(" "))
}

var bestPixels = Set.empty[Point]
for (n <- 0 until area) {                                                                                                                                                                                          
  val pixels = generate(n)
  if (pixels.size > bestPixels.size) bestPixels = pixels
}
print(bestPixels)

산출

302 303 305 309 314 322 332 346 367 382 398 424 449 483 505 553 591 619 647 680 719 813 862 945 1014 1247 1459 1700 1740 1811 1861 1979 2301 2511 2681 2913 3114 3262 3368 4253 4483 4608 4753 5202 5522 5760 6246 6474 6579 6795 7498 8062 8573 8664 9903 10023 10567 10790 11136 12000 14153 15908 17314 17507 19331 20563 20941 22339 25131 26454 28475 31656 38328 39226 40214 50838 53240 56316 60690 61745 62374 68522 71208 78598 80204 86005 89218 93388 101623 112924 115702 118324 123874 132852 136186 139775 144948 154274 159730 182200 193642 203150 203616 213145 214149 218519 219744 226729 240795 243327 261196 262036 271094 278680 282306 289651 303297 311298 315371 318124 321962 330614 336472 343091 346698 354881 359476 361983 366972 369552 380486 382491

3
그냥 ... 공 회전을 얻기
데이브 스와 츠

3

파이썬 134 132

다음은 더 넓은 영역을 커버하기 위해 일부 검색 공간을 무작위로 컬링하는 간단한 것입니다. 원점 순서에서 멀리 떨어진 지점을 반복합니다. 원점에서 같은 거리에있는 점을 건너 뛰고, 최고점을 개선 할 수없는 경우에는 조기 종료합니다. 무한정 실행됩니다.

from random import *
from bisect import *

W = H = 619
pts = []
deepest = 0
lengths = set()

def place(x, y):
    global lengths
    pos = (x, y)
    for px, py in pts:
        dist = (x-px)*(x-px) + (y-py)*(y-py)
        if dist in lengths:
            return False
    dists = set((x-px)*(x-px) + (y-py)*(y-py) for px, py in pts)
    if len(dists) != len(pts):
        return False
    lengths |= dists
    pts.append(pos)
    return True

def unplace():
    x, y = pos = pts.pop()
    for px, py in pts:
        dist = (x-px)*(x-px) + (y-py)*(y-py)
        lengths.remove(dist)

def walk(i):
    global deepest, backtrack
    depth = len(pts)
    while i < W*H:
        d, x, y, rem = order[i]
        if rem+depth <= deepest: # early out if remaining unique distances mean we can't improve
            return
        i += 1
        if place(x, y):
            j = i
            while j < W*H and order[j][0] == d: # skip those the same distance from origin
                j += 1
            walk(j)
            unplace()
            if backtrack <= depth:
                break
            if not randint(0, 5): # time to give up and explore elsewhere?
                backtrack = randint(0, len(pts))
                break
            backtrack = W*H # remove restriction
    if depth >= deepest:
        deepest = depth
        print (ox, oy), depth, "=", " ".join(str(y*W+x) for x, y in pts)

try:
    primes = (0,1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97)
    while True:
        backtrack = W*H
        ox, oy = choice(primes), choice(primes) # random origin coordinates
        order = sorted((float((ox-x)**2+(oy-y)**2)+random(), x, y) for x in xrange(W) for y in xrange(H))
        rem = sorted(set(int(o[0]) for o in order)) # ordered list of unique distances
        rem = {r: len(rem)-bisect_right(rem, r) for r in rem} # for each unique distance, how many remain?
        order = tuple((int(d), x, y, rem[int(d)]) for i, (d, x, y) in enumerate(order))
        walk(0)
except KeyboardInterrupt:
    print

134 포인트의 솔루션을 빠르게 찾습니다.

3097 3098 2477 4333 3101 5576 1247 9 8666 8058 12381 1257 6209 15488 6837 21674 19212 26000 24783 1281 29728 33436 6863 37767 26665 14297 4402 43363 50144 52624 18651 9996 58840 42792 6295 69950 48985 34153 10644 72481 83576 63850 9935 1393 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 33 33 13 남 125,201 151,128 115,936 165,898 127,697 162,290 33,091 20,098 189,414 187,620 186,440 91,290 206,766 35,619 69,033 351 186,511 129,058 228,458 69,065 226,046 210,035 235,925 164,324 18,967 254,416 130,970 17,753 248,978 57,376 276,798 456 283,541 293,423 257,747 204,626 298,427 135,610 31,796 4,570 150,418 57,797 4,581 113,313 88,637 122,569 11,956 36,098 79,401 61,471 249115 21544 95185 231226 54354 104483 280665 518147181 318363 1793 248609 82260 52568 365227 361603 346849 331462 69310 90988 341446 229599 277828 382837 339014 323612 365040 269883 307597 374347 316282 354625 339821 372016

궁금한 점은 다음과 같습니다.

3  =  0  2  3
4  =  0  2  4  7
5  =  0  2  5 17 23
6  =  0 12 21 28 29 30
7  =  4  6 11 14 27 36 42
8  =  0  2  8 11 42 55 56
9  =  0  2  9 12 26 50 63 71
10 =  0  2  7 10 35 75 86 89  93
11 =  0 23 31 65 66 75 77 95 114 117

PyPy를 통해 이것을 시도 했습니까 ?
trichoplax

1
@ trichoplax 나는 항상 파이썬과 파이썬 모두 에서이 취미를 실행하며, 파이썬이 더 빠르면 파이썬에 티켓을 싣습니다. 이 특별한 경우에, pypy는 cpython보다 약간 빠르며, 이것이 내가이 숫자들을 얻는 방법입니다 :)
Will

관심이 있습니다. "빠른"내용은 무엇입니까?
가인

'빨리'@Cain IIRC 5 분에 있었다

2

팬텀 96

나는 진화 알고리즘을 사용하여 기본적으로 한 번에 k 개의 랜덤 포인트를 추가하고 j 개의 다른 랜덤 세트에 대해 수행 한 다음 가장 좋은 것을 선택하고 반복하십시오. 지금은 꽤 끔찍한 대답이지만 속도를 위해 세대당 2 명의 자녀만이 실행되고 있습니다. 이는 거의 무작위입니다. 어떻게 진행되는지 확인하기 위해 매개 변수를 약간 사용하여 갈 수 있으며, 남은 무료 지점보다 더 나은 점수 기능이 필요할 것입니다.

class Pixel
{
  static const Int n := 619
  static const Int stepSize := 20
  static const Int generationSize := 5
  static const |Int, Int -> Int| d := |Int x, Int y -> Int| {
      d1 := x%n - y%n
      d2 := x/n - y/n
      return d1.pow(2) + d2.pow(2)
    }


  public static Void main(){

    //Initialize

    [Int: Int[][]] disMap := [:]
    Int[] freeSpots := (0..<n*n).toList
    Int[] pixels := [,]
    Int[] distances := [,]





    genNum := 0
    children := [,]
    while(freeSpots.size > 0){
      echo("Generation: ${genNum++} \t Spots Left: ${freeSpots.size} \t Pixels added: $pixels.size \t Distances used: $distances.size uniqueDistances: $distances.unique.size" )
      echo(distances)
      echo("Pixels: " + pixels.join(" "))
      //echo("Distances: $distances")
      //Generate children
      children = [,]
      generationSize.times{
        //echo("\tStarting child $it")
        i := Int.random(0..<freeSpots.size)
        childFreeSpots := freeSpots.dup
        childPixels := pixels.dup
        childDistances := distances.dup

        for(Int step := 0; step < stepSize; step++){

          if( i < childFreeSpots.size){
            //Choose a pixel
            pixel := childFreeSpots.removeAt(i)
            //echo("\t\tAdding pixel $pixel")

            //Remove neighbors that are the new distances away
            ///Find distances
            newDis := [,]
            childPixels.each { 
              newDis.add(d(pixel, it))
            }

            //Check that there are no equal distances
            if(newDis.size != newDis.unique.size) continue



            //Remove neighbors
            childPixels.each | Int childPixel|{
              newDis.each |Int dis|{
                neighbors := getNeighbors(childPixel, dis, disMap)
                neighbors.each| Int n |{
                  index := childFreeSpots.binarySearch(n)
                  if(index >= 0) childFreeSpots.removeAt(index)
                }
              }
            }
            //echo("Removed neighbors: $test")
            //Remove all the neighbors of new pixel
            childDistances.addAll(newDis)
            childDistances.each|Int dis| {   
              neighbors := getNeighbors(pixel, dis, disMap)
              childFreeSpots.removeAll(neighbors)
            }

            //Add new pixel
            childPixels.add(pixel)  
          }
        }
        children.add([childPixels.dup, childDistances.dup, childFreeSpots.dup])
        echo("\tChild $it: pixels: $childPixels.size \t distances: $childDistances.size \t freeSpots: $childFreeSpots.size")
      }

      //Score children and keep best one as new parent
      Obj?[][] parent := children.max |Int[][] a, Int[][] b -> Int| { return (a.last.size  + a.first.size*10000) <=> (b.last.size + b.first.size*10000)  }
      pixels = parent.first
      distances = parent[1]
      freeSpots = parent.last

    }//End while


    //Return result
    echo("Size: " + pixels.size)
    echo(pixels.join(" "))





  }

  private static Bool checkValid(Int[] pixels){
    distances := [,]
    pixels[0..-2].each|Int p, Int i|{
      for(Int j := i + 1; j < pixels.size; j++){
        distances.add(d(p, pixels[j]))
      }
    }
    if(distances.size > distances.unique.size){
      echo("Duplicate distance found!!!!")
      echo("Pixel $pixels.last is not valid")
      return false
    }
    return true
  }

  public static Int[] getNeighbors(Int spot, Int distance, [Int : Int[][]] disMap ){
    result := [,]
    //Check hash map
    pairs := disMap.get(distance, null)

    //Find possible int pairs if not already in the map
    if(pairs == null){
      for(Int i := 0; i*i <= distance; i++ ){
        for(Int j := i; j*j + i*i <= distance; j++){
          if(i.pow(2) + j.pow(2) == distance){
            pairs.add([i, j])
          }
        }
      }
      disMap.add(distance, pairs)
    }

    pairs.each|Int[] pair|{
      //Find neighbors with pair
      x := pair.first
      y := pair.last
      2.times{ 
        //Positive x
        result.add(spot + x + y*n)
        result.add(spot + x - y*n)

        //negative x
        result.add(spot - x + y*n)
        result.add(spot - x - y*n)

        //Swap x and y and repeat
        temp := x
        x = y
        y = temp
      }
    }

    return result.findAll |Int i -> Bool| { i >= 0 }.unique
  }

}

산출

17595 17596 17601 17627 17670 17726 17778 17861 17956 18117 18324 18733 19145 19597 20244 21139 21857 22742 24078 25343 28577 30152 32027 34406 37008 39864 42313 44820 48049 52193 55496 59707 64551 69976 74152 79758 84392 91782 98996 104625 150212 158877 169579 178660 189201 201343 213643 225998 238177 251012 263553 276797 290790 304915 319247 332702 347266 359665 373683 125899 144678 170677 195503 220092 244336 269861 289473 308633 326736 343756 358781 374280 131880 172485 212011 245015 277131 302055 321747 347911 363717 379166 249798 284200 313870 331913 360712 378024 9704 141872 249686 293656 357038 357596 370392 381963

1
오 와우, 네 말이 맞아 미안해 흠, 내가 테스트 할 때 일찍 그것을 복사하지 않았어야합니다. 나는 무슨 일이 일어나고 있는지 수정하고 업데이트로 응답합니다.
Cain

아, 나는 새로운 픽셀을 추가 할 때, 나는 그것이 다른 두 픽셀에서 같은 거리에 아니라고 확인되지 않았다 그것을 알아 냈다
가인

문제를 해결했지만 지금은 정말 짜증납니다. 우연히 최선의 해결책 대신에 최악의 해결책을 찾은 것 같습니다
Cain

적어도 지금은 작동하므로 매개 변수를 조정하고 결과를 향상시킬 수 있는지 확인할 수 있습니다. 또 다른 새로운 접근 방식을 보게되어 좋습니다. +1
trichoplax

1

파이썬 3, 119

mc_uspMarkov 체인과 관련이 있다고 생각하지만 더 이상이 기능의 이름을 기억하지 못합니다 . 여기에 약 7 시간 동안 PyPy로 실행 한 코드를 게시합니다. 이 프로그램은 이미지의 모든 픽셀을 검사 할 때까지 픽셀을 임의로 선택하여 최상의 세트 중 하나를 반환하여 100 개의 서로 다른 픽셀 세트를 만들려고합니다.

또 다른 참고로, 어떤 시점에서, 우리는 실제로 N=619488보다 나은 상한을 찾으려고 시도해야 합니다. 여기의 답변에서 판단하면 그 수는 너무 높습니다. 모든 새로운 포인트가 최적의 선택으로 포인트를 제거 할 수있는 방법에 대한 Rowan Blush의 의견 은 좋은 생각처럼 보였습니다. 불행하게도, 식의 검사에 여기서 추가 한 후 제거 점의 수입니다 우리의 세트 포인트가,이 아이디어는 가장 적합하지 않을 수 있습니다. 때 검사 보다 큰 , 보다 큰 것은 약속 보이지만 보다 더 큰 것입니다 . 더 나은 상한선을 보려고 노력할 때 계속 게시하겠습니다. 그러나 어떤 제안이라도 환영합니다.n+16*na(1) = 1; a(n+1) = a(n) + 6*n + 1a(n)na(n)N**2a(200)619**2a(n)10**2a(7) 우리는 9 위 행 실제임을 입증했습니다N=10

내 대답에. 먼저, 119 픽셀 세트입니다.

15092 27213 294010 340676 353925 187345 127347 21039 28187 4607 23476 324112 375223 174798 246025 185935 186668 138651 273347 318338 175447 316166 158342 97442 361309 251283 29986 98029 339602 292202 304041 353401 236737 324696 42096 102574 357602 66845 40159 57866 3291 24583 254208 357748 304592 86863 19270 228963 87315 355845 55101 282039 83682 55643 292167 268632 118162 48494 378303 128634 117583 841 178939 20941 161231 247142 110205 211040 90946 170124 362592 327093 336321 291050 29880 279825 212675 138043 344012 187576 168354 28193 331713 329875 321927 129452 163450 1949 186448 50734 14422 3761 322400 318075 77824 36391 31016 33491 360713 352240 45316 79905 376004 310778 382640 383077 359178 14245 275451 362125 268047 23437 239772 299047 294065 46335 112345 382617 79986

둘째, 내 코드는 619x619 정사각형의 옥탄트에서 시작점을 임의로 선택합니다 (시작점이 달리 회전 및 반사에서 동일하기 때문에). 그런 다음 정사각형의 나머지 부분에서 다른 모든 점.

import random
import time

start_time = time.time()
print(start_time)

def mc_usp_v3(N, z, k=100, m=1.0):
    """
    At m=1.0, it keeps randomly picking points until we've checked every point. Oh dear.
    """
    ceil = -(-N//2)
    a=random.randint(0,ceil)
    b=random.randint(a,ceil)
    r=[a*N+b]

    best_overall = r[:]
    all_best = []
    best_in_shuffle = r[:]
    num_shuffles = 0
    num_missteps = 0
    len_best = 1

    while num_shuffles < k and len(best_overall) < z:
        dist = []
        missteps = []
        points_left = list(range(N*N))
        points_left.remove(r[0])

        while len_best + num_missteps < m*N*N and len(points_left):
            index = random.randint(0, len(points_left)-1)
            point = points_left[index]
            points_left.pop(index)
            dist, better = euclid(r, point, dist, N)

            if better and len(r) + 1 > len_best:
                r.append(point)
                best_in_shuffle = r[:]
                len_best += 1
            else:
                missteps.append(point)
                num_missteps += 1

        else:
            print(num_shuffles, len(best_overall), len_best, num_missteps, time.time() - start_time)

            num_shuffles += 1
            num_missteps = 0
            missteps = []

            if len(best_in_shuffle) == len(best_overall):
                all_best.append(best_in_shuffle)
                print(best_in_shuffle)

            if len(best_in_shuffle) > len(best_overall):
                best_overall = best_in_shuffle[:]
                all_best = [best_overall]
                print(best_overall)
            a=random.randint(0,ceil)
            b=random.randint(a,ceil)
            r=[a*N+b]
            best_in_shuffle = r[:]
            len_best = 1
    return len(best_overall), all_best

def euclid(point_set, new_point, dist, N):
    new_dist = []
    unique = True
    a,b=divmod(new_point, N)
    for point in point_set:
        c,d=divmod(point, N)
        current_dist = (a-c)**2+(b-d)**2
        if current_dist in dist or current_dist in new_dist:
            unique = False
            break
        new_dist.append(current_dist)
    if unique:
        dist += new_dist
    return dist, unique

def mcusp_format(mcusp_results):
    length, all_best = mcusp_results
    return " ".join(str(i) for i in all_best[0])

print(mcusp_format(mc_usp_v3(10, 20, 100, 1.0)))
print(mcusp_format(mc_usp_v3(619, 488, 100, 1.0)))
print(time.time()-start_time)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.