고유하게 분리 된 픽셀 매겨진 픽셀 중 하나를

들어 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


스택 스 니펫 판사

canvas=document.getElementById('canvas');ctx=canvas.getContext('2d');information=document.getElementById('information');problemList=document.getElementById('problemList');width=canvas.width;height=canvas.height;area=width*height;function verify(){stop();checkPoints();}function checkPoints(){valid=true;numbers=[];points=[];lengths=[];lengthDetails=[];duplicatedLengths=[];clearCanvas();rawData=pointData.value;splitData=rawData.split(' ');for(i=0;i<splitData.length;i++){datum=splitData[i];if(datum!==''){n=parseInt(datum);if(n>=area||n<0){valid=false;information.innerHTML='Out of range:'+n;break;}if(numbers.indexOf(n)>-1){valid=false;information.innerHTML='Duplicated value:'+n;break;}numbers.push(n);x=n%width;y=Math.floor(n/width);points.push([x,y]);}}if(valid){ctx.fillStyle='black';for(i=0;i<points.length-1;i++){p1=points[i];x1=p1[0];y1=p1[1];drawPoint(x1,y1);for(j=i+1;j<points.length;j++){p2=points[j];x2=p2[0];y2=p2[1];d=distance(x1,y1,x2,y2);duplicate=lengths.indexOf(d);if(duplicate>-1){duplicatedLengths.push(lengthDetails[duplicate]);duplicatedLengths.push([d,[numbers[i],numbers[j]],[x1,y1,x2,y2]]);}lengths.push(d);lengthDetails.push([d,[numbers[i],numbers[j]],[x1,y1,x2,y2]]);}}p=points[points.length-1];x=p[0];y=p[1];drawPoint(x,y);if(duplicatedLengths.length>0){ctx.strokeStyle='red';information.innerHTML='Duplicate lengths shown in red';problemTextList=[];for(i=0;i<duplicatedLengths.length;i++){data=duplicatedLengths[i];length=data[0];numberPair=data[1];coords=data[2];line(coords);specificLineText='<b>'+length+': '+numberPair[0]+' to '+numberPair[1]+'</b> [('+coords[0]+', '+coords[1]+') to ('+coords[2]+', '+coords[3]+')]';if(problemTextList.indexOf(specificLineText)===-1){problemTextList.push(specificLineText);}}problemText=problemTextList.join('<br>');problemList.innerHTML=problemText;}else{information.innerHTML='Valid: '+points.length+' points';}}}function clearCanvas(){ctx.fillStyle='white';ctx.fillRect(0,0,width,height);}function line(coords){x1=coords[0];y1=coords[1];x2=coords[2];y2=coords[3];ctx.beginPath();ctx.moveTo(x1+0.5,y1+0.5);ctx.lineTo(x2+0.5,y2+0.5);ctx.stroke();}function stop(){information.innerHTML='';problemList.innerHTML='';}function distance(x1,y1,x2,y2){xd=x2-x1;yd=y2-y1;return Math.sqrt(xd*xd+yd*yd);}function drawPoint(x,y){ctx.fillRect(x,y,1,1);}
<input id='pointData' placeholder='Paste data here' onblur='verify()'></input><button>Verify data</button><p id='information'></p><p id='problemList'></p><canvas id='canvas' width='619' height='619'></canvas>


답변

파이썬 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있어 (그러나 이것은했다 많은 미세 조정 및 다른 초기 점을 노력을) :

암호

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)

답변

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]

스택 스 니펫의 이미지


답변

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

답변

파이썬 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

스택 스 니펫의 이미지


답변

파이썬 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)

답변

스칼라, 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

답변

파이썬 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