Các pixel riêng biệt


30

Đối với một N bởi N hình ảnh, hãy tìm một tập hợp các pixel như vậy mà không khoảng cách tách biệt hiện diện nhiều hơn một lần. Nghĩa là, nếu hai pixel cách nhau một khoảng cách d , thì chúng là hai pixel duy nhất được phân tách bằng chính xác d (sử dụng khoảng cách Euclide ). Lưu ý rằng d không cần phải là số nguyên.

Thách thức là tìm ra một bộ lớn hơn như vậy hơn bất kỳ ai khác.

Đặc điểm kỹ thuật

Không có đầu vào là bắt buộc - đối với cuộc thi này, N sẽ được sửa ở mức 619.

(Vì mọi người cứ hỏi - không có gì đặc biệt về số 619. Nó được chọn đủ lớn để tạo ra một giải pháp tối ưu khó có thể, và đủ nhỏ để hiển thị hình ảnh N by N mà không cần Stack Exchange tự động thu nhỏ nó. hiển thị kích thước đầy đủ lên tới 630 x 630 và tôi đã quyết định sử dụng số nguyên tố lớn nhất không vượt quá.)

Đầu ra là một danh sách các số nguyên được phân tách bằng dấu cách.

Mỗi số nguyên trong đầu ra đại diện cho một trong các pixel, được đánh số theo thứ tự đọc tiếng Anh từ 0. Ví dụ: đối với N = 3, các vị trí sẽ được đánh số theo thứ tự này:

0 1 2
3 4 5
6 7 8

Bạn có thể xuất thông tin tiến trình trong khi chạy nếu bạn muốn, miễn là đầu ra cho điểm cuối cùng có sẵn. Bạn có thể xuất ra STDOUT hoặc vào một tệp hoặc bất cứ thứ gì dễ nhất để dán vào Thẩm phán đoạn trích dưới đây.

Thí dụ

N = 3

Tọa độ chọn:

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

Đầu ra:

0 1 5

Chiến thắng

Điểm số là số lượng vị trí trong đầu ra. Trong số những câu trả lời hợp lệ có số điểm cao nhất, sớm nhất để đăng đầu ra với số điểm đó sẽ thắng.

Mã của bạn không cần phải xác định. Bạn có thể đăng sản lượng tốt nhất của bạn.


Các lĩnh vực liên quan để nghiên cứu

(Cảm ơn Abulafia vì các liên kết Golomb)

Mặc dù cả hai vấn đề này đều không giống với vấn đề này, cả hai đều giống nhau về khái niệm và có thể cung cấp cho bạn ý tưởng về cách tiếp cận vấn đề này:

Lưu ý rằng các điểm cần thiết cho câu hỏi này không phải tuân theo các yêu cầu giống như hình chữ nhật Golomb. Hình chữ nhật Golomb mở rộng từ trường hợp 1 chiều bằng cách yêu cầu vectơ từ mỗi điểm này với nhau là duy nhất. Điều này có nghĩa là có thể có hai điểm cách nhau 2 khoảng cách theo chiều ngang và cũng có hai điểm cách nhau khoảng cách 2 theo chiều dọc.

Đối với câu hỏi này, đó là khoảng cách vô hướng phải là duy nhất, do đó không thể có cả phân tách ngang và dọc là 2. Mọi giải pháp cho câu hỏi này sẽ là một hình chữ nhật Golomb, nhưng không phải mọi hình chữ nhật Golomb sẽ là một giải pháp hợp lệ cho câu hỏi này.


Giới hạn trên

Dennis hữu ích chỉ ra trong trò chuyện rằng 487 là giới hạn trên của điểm số và đưa ra một bằng chứng:

Theo mã CJam của tôi ( 619,2m*{2f#:+}%_&,), có 118800 số duy nhất có thể được viết dưới dạng tổng bình phương của hai số nguyên nằm trong khoảng từ 0 đến 618 (bao gồm cả hai). n pixel yêu cầu n (n-1) / 2 khoảng cách duy nhất giữa nhau. Với n = 488, nó mang lại 118828.

Vì vậy, có 118.800 độ dài khác nhau có thể có giữa tất cả các pixel tiềm năng trong ảnh và đặt 488 pixel đen sẽ tạo ra 118.828 độ dài, khiến tất cả chúng không thể là duy nhất.

Tôi rất muốn biết liệu có ai có bằng chứng về giới hạn trên thấp hơn mức này không.


Bảng xếp hạng

(Câu trả lời hay nhất của mỗi người dùng)

hình ảnh bảng xếp hạng


Chồng đánh giá Snippet


Tôi rất thích nhìn thấy câu trả lời của Piet ở đây
C5H8NNaO4

@ C5H8NNaO4 cuộc thi đã kết thúc - không có ai ở gần một giải pháp tối ưu nên có nhiều chỗ cho câu trả lời mới ...
trichoplax

Vì bạn đang cung cấp tiền thưởng cho cả danh sách pixel đã được chứng minh ở trên và thử nghiệm, tôi cho rằng có một loại ứng dụng nào đó cho vấn đề này?
Gây tử vong vào

@Firthize không phải là tôi biết, nhưng tôi rất thích nghe về một. Vấn đề tương tự mảng Costas có các ứng dụng thực tế được liệt kê nhưng tôi không tìm thấy gì về vấn đề cụ thể này.
trichoplax

1
Tôi đã xem xét điều này và tôi tin rằng n = 487 là giới hạn trên tối thiểu trên pixel. Vì tò mò, bạn sẽ chấp nhận một bằng chứng rằng không có giới hạn trên cho tiền thưởng?
Mego

Câu trả lời:


13

Trăn 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

Được tìm thấy bằng thuật toán tham lam, ở mỗi giai đoạn, chọn pixel hợp lệ có tập khoảng cách đến các pixel được chọn trùng với ít nhất so với các pixel khác.

Cụ thể, cách tính điểm là

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

và pixel có điểm thấp nhất được chọn.

Tìm kiếm được bắt đầu với điểm 10(nghĩa là(0, 10) ). Phần này có thể điều chỉnh, do đó, bắt đầu với các pixel khác nhau có thể dẫn đến kết quả tốt hơn hoặc xấu hơn.

Đây là một thuật toán khá chậm, vì vậy tôi đang cố gắng thêm tối ưu hóa / heuristic và có thể một số quay lại. PyPy được khuyến nghị cho tốc độ.

Bất cứ ai đang cố gắng đưa ra một thuật toán nên thử nghiệm N = 10, trong đó tôi đã có 9 (nhưng điều này cần rất nhiều điều chỉnh và thử các điểm ban đầu khác nhau):

nhập mô tả hình ảnh ở đây

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
Tôi nhanh chóng bắt buộc N=10và có nhiều bố cục riêng biệt với 9 điểm nhưng đó là cách tốt nhất bạn có thể làm.
Sẽ

5

SWI-Prolog, điểm số 131

Khá tốt hơn câu trả lời ban đầu, nhưng tôi đoán điều này sẽ khiến mọi thứ bắt đầu nhiều hơn một chút. Thuật toán giống như câu trả lời của Python ngoại trừ việc nó thử pixel theo cách khác, bắt đầu bằng pixel trên cùng bên trái (pixel 0), sau đó là pixel dưới cùng bên phải (pixel 383160), rồi pixel 1, rồi pixel 383159 v.v.

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).

Đầu vào:

a(A).

Đầu ra:

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]

Hình ảnh từ Stack Snippet

131 điểm


Vì có tối đa lý thuyết là 487, thậm chí mức tăng gia tăng cũng rất đáng kể ...
trichoplax

Đầu ra của bạn như được hiển thị có hoạt động với Stack Snippet không? Tôi đã chỉ định không gian được phân tách (như trong câu trả lời ví dụ của tôi) nhưng lý do chính cho điều đó là để Snippet Stack hoạt động.
trichoplax

@trichoplax Vâng, đó là một lỗi đánh máy, tôi bắt đầu với pixel 0, tôi sẽ sửa nó. Để có được hình ảnh, tôi đã chọn một phần của đầu ra giữa hai dấu ngoặc vuông và xóa tất cả dấu phẩy. Đoạn mã Stack dường như hoạt động với các pixel được phân tách bằng dấu phẩy.
Gây tử vong vào

4

Haskell trên 115 130 131 135 136

Cảm hứng của tôi là Sàng của Eratosthenes và đặc biệt là Sàng chính xác của Eratosthenes , một bài báo của Melissa E. O'Neill của Harvey Mudd College. Phiên bản gốc của tôi (được coi là điểm theo thứ tự chỉ mục) đã sàng điểm cực kỳ nhanh chóng, vì một số lý do tôi không thể nhớ lại, tôi đã quyết định xáo trộn các điểm trước khi sám sát vào chúng trong phiên bản này (tôi nghĩ chỉ để tạo ra các câu trả lời khác nhau dễ dàng hơn bằng cách sử dụng một hạt giống mới trong máy phát ngẫu nhiên). Bởi vì các điểm không còn theo bất kỳ thứ tự nào nữa, thực sự không còn bất kỳ sự sàng lọc nào xảy ra nữa, và kết quả là phải mất vài phút chỉ để đưa ra câu trả lời 115 điểm duy nhất này. Một loại trực tiếp Vectorcó lẽ sẽ là một lựa chọn tốt hơn bây giờ.

Vì vậy, với phiên bản này như là một điểm kiểm tra, tôi thấy hai nhánh, quay trở lại thuật toán của S Chính xác của Sàng, và sử dụng danh sách đơn vị để lựa chọn hoặc hoán đổi các Setthao tác tương đương Vector.

Chỉnh sửa: Vì vậy, đối với phiên bản làm việc hai, tôi đã quay trở lại thuật toán sàng, đã cải thiện việc tạo ra các bội số của Google (loại bỏ các chỉ số bằng cách tìm các điểm tại tọa độ nguyên trên các vòng tròn có bán kính bằng khoảng cách giữa hai điểm bất kỳ, giống như tạo ra bội số nguyên tố ) và thực hiện một vài cải tiến thời gian liên tục bằng cách tránh một số tính toán lại không cần thiết.

Vì một số lý do, tôi không thể biên dịch lại với hồ sơ được bật, nhưng tôi tin rằng nút cổ chai lớn hiện đang quay trở lại. Tôi nghĩ rằng việc khám phá một chút song song và đồng thời sẽ tạo ra sự tăng tốc tuyến tính, nhưng sự cạn kiệt bộ nhớ có thể sẽ giúp tôi cải thiện gấp đôi.

Chỉnh sửa: Phiên bản 3 uốn khúc một chút, lần đầu tiên tôi thử nghiệm một heuristic trong việc lấy các chỉ số tiếp theo (sau khi sàng từ các lựa chọn trước đó) và chọn một trong đó tạo ra bộ loại trực tiếp tối thiểu tiếp theo. Điều này đã kết thúc quá chậm, vì vậy tôi đã quay trở lại một phương pháp vũ phu toàn bộ không gian tìm kiếm. Một ý tưởng để sắp xếp các điểm theo khoảng cách từ một số nguồn gốc đã đến với tôi, và dẫn đến một sự cải thiện bởi một điểm duy nhất (trong thời gian sự kiên nhẫn của tôi kéo dài). Phiên bản này chọn chỉ số 0 làm gốc, có thể đáng để thử điểm trung tâm của mặt phẳng.

Chỉnh sửa: Tôi đã chọn 4 điểm bằng cách sắp xếp lại không gian tìm kiếm để ưu tiên các điểm xa nhất từ ​​trung tâm. Nếu bạn đang thử nghiệm mã của tôi, 135 136 thực sự là thứ hai giải pháp thứ ba được tìm thấy. Chỉnh sửa nhanh: Phiên bản này có vẻ như có khả năng duy trì hiệu quả cao nhất nếu còn chạy. Tôi nghi ngờ tôi có thể buộc ở mức 137, sau đó hết kiên nhẫn chờ đợi 138.

Một điều tôi nhận thấy (có thể giúp ích cho ai đó) là nếu bạn đặt thứ tự điểm từ tâm của mặt phẳng (nghĩa là xóa (d*d -)khỏi originDistance), hình ảnh được tạo ra trông hơi giống hình xoắn ốc thưa thớt.

{-# 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

Đầu ra

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

Những cải tiến ấn tượng. Bạn còn 2 giờ để đến 138 trước khi tiền thưởng được chỉ định. Dù sao thì cũng rất tuyệt ...
trichoplax

Có vẻ như tôi sẽ không đạt được mục tiêu đó, tôi vẫn không thể tạo ra một bộ phần tử 137. Tôi nghĩ rằng phương pháp này có thể được khai thác ...
RB

Điều thú vị là hai câu trả lời khác nhau với các cách tiếp cận khác nhau đang đạt mức tối đa xung quanh cùng kích thước.
trichoplax

Tôi nghĩ rằng giới hạn trên có lẽ là khá gần. Xét một mặt phẳng vô hạn và hai điểm bất kỳ. Vị trí tối ưu của các điểm đó với bất kỳ khoảng cách nào sẽ dgiảm thiểu số lượng các điểm khác được loại trừ khỏi việc xem xét bằng cách truy tìm các vòng tròn bán kính dvới tâm của cả hai điểm được chọn, trong đó chu vi chỉ chạm vào ba tọa độ nguyên khác (ở 90, 180 và 270 độ quay đường tròn) và đường thẳng chia đôi vuông góc không có tọa độ nguyên. Vì vậy, mỗi điểm mới n+1sẽ loại trừ 6ncác điểm khác khỏi sự cân nhắc (với sự lựa chọn tối ưu).
RB

3

Trăn 3, điểm 129

Đây là một câu trả lời ví dụ để bắt đầu mọi thứ.

Chỉ là một cách tiếp cận ngây thơ đi qua các pixel theo thứ tự và chọn pixel đầu tiên không gây ra khoảng cách phân tách trùng lặp, cho đến khi hết pixel.

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()

Đầu ra

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

Hình ảnh từ Stack Snippet

hình ảnh của 129 pixel tách biệt


3

Trăn 3, 130

Để so sánh, đây là một triển khai backtracker đệ quy:

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)

Nó nhanh chóng tìm thấy giải pháp 130 pixel trước khi bắt đầu nghẹt thở:

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

Quan trọng hơn, tôi đang sử dụng nó để kiểm tra các giải pháp cho các trường hợp nhỏ. Đối với N <= 8, tối ưu là:

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)

Được liệt kê trong ngoặc là những tối ưu từ vựng đầu tiên.

Chưa được xác nhận:

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

Scala, 132

Quét từ trái sang phải và từ trên xuống dưới như giải pháp ngây thơ, nhưng cố gắng bắt đầu ở các vị trí pixel khác nhau.

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)

Đầu ra

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
Chỉ cần làm cho quả bóng lăn ...
Dave Swartz

3

Con trăn, 134 132

Đây là một cái đơn giản mà ngẫu nhiên loại bỏ một số không gian tìm kiếm để bao phủ một khu vực lớn hơn. Nó lặp lại các điểm trong khoảng cách từ một lệnh gốc. Nó bỏ qua các điểm có cùng khoảng cách với nguồn gốc và xuất phát sớm nếu nó không thể cải thiện tốt nhất. Nó chạy vô thời hạn.

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

Nó nhanh chóng tìm ra giải pháp với 134 điểm:

3097 30 Tê 1 249115 21544 95185 231226 54354 104483 280665 518 147181 318363 1793 2489

Đối với những người tò mò, đây là một số N nhỏ bị ép buộc:

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

Bạn đã thử chạy nó qua PyPy chưa?
trichoplax

1
@trichoplax Tôi luôn chạy những thứ sở thích này trên cả pypy và cpython, và nếu cpython nhanh hơn tôi sẽ đặt vé trên pypy. Trong trường hợp cụ thể này, pypy nhanh hơn một chút so với cpython và đó là cách tôi có được những con số này :)
Will

Tôi quan tâm, "nhanh chóng" đòi hỏi gì?
Cain

@Cain 'nhanh chóng' là khoảng 5 phút iirc
Will

2

Tưởng tượng 96

Tôi đã sử dụng một thuật toán tiến hóa, về cơ bản thêm k điểm ngẫu nhiên tại một thời điểm, làm điều đó cho j các tập ngẫu nhiên khác nhau, sau đó chọn điểm tốt nhất và lặp lại. Câu trả lời khá khủng khiếp ngay bây giờ, nhưng đó chỉ là chạy 2 đứa trẻ mỗi thế hệ vì tốc độ, gần như chỉ là ngẫu nhiên. Gonna chơi với các tham số một chút để xem nó diễn ra như thế nào và tôi có lẽ cần một chức năng ghi điểm tốt hơn số lượng điểm miễn phí còn lại.

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
  }

}

Đầu ra

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
Ồ wow, bạn nói đúng, tôi xin lỗi. Hmm, phải không sao chép tất cả sớm khi tôi kiểm tra. Tôi sẽ khắc phục mọi thứ đang diễn ra và phản hồi với bản cập nhật
Cain

À, tôi đã nhận ra rồi, khi thêm một pixel mới, tôi đã không kiểm tra xem nó không tương đương với hai pixel khác
Cain

Đã sửa nó, nhưng nó thực sự rất tệ, tôi nghĩ rằng tôi có thể đang vô tình tìm ra giải pháp tồi tệ nhất thay vì giải pháp tốt nhất
Cain

Ít nhất là nó hoạt động ngay bây giờ, vì vậy bạn có thể điều chỉnh các tham số và xem liệu bạn có thể cải thiện kết quả hay không. Tuyệt vời để xem một cách tiếp cận mới. +1
trichoplax

1

Con trăn 3, 119

Tôi không còn nhớ tại sao tôi đặt tên cho chức năng này mc_usp , mặc dù tôi nghi ngờ nó có liên quan đến chuỗi Markov. Ở đây tôi xuất bản mã của mình mà tôi đã chạy với PyPy trong khoảng 7 giờ. Chương trình cố gắng xây dựng 100 bộ pixel khác nhau bằng cách chọn ngẫu nhiên các pixel cho đến khi nó kiểm tra từng pixel trong ảnh và trả về một trong những bộ tốt nhất.

Một lưu ý khác, tại một số điểm, chúng tôi thực sự nên cố gắng tìm giới hạn trên cho N=619điều đó tốt hơn 488, bởi vì đánh giá từ các câu trả lời ở đây, con số đó quá cao. Nhận xét của Rowan Blush về cách mọi điểm mới n+1có khả năng loại bỏ 6*ncác điểm với lựa chọn tối ưu dường như là một ý tưởng tốt. Thật không may, khi kiểm tra công thức a(1) = 1; a(n+1) = a(n) + 6*n + 1, a(n)số điểm bị xóa sau khi thêm nđiểm vào tập hợp của chúng tôi, ý tưởng này có thể không phù hợp nhất. Kiểm tra khi nào a(n)lớn hơn N**2, a(200)lớn hơn 619**2có vẻ hứa hẹn, nhưng a(n)lớn hơn10**2a(7) và chúng tôi đã chứng minh rằng 9 là thực tế trên ràng buộc choN=10. Tôi sẽ thông báo cho bạn khi tôi cố gắng tìm kiếm giới hạn trên tốt hơn, nhưng mọi đề xuất đều được chào đón.

Lên câu trả lời của tôi Đầu tiên, bộ 119 pixel của tôi.

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

Thứ hai, mã của tôi, chọn ngẫu nhiên một điểm bắt đầu từ một quãng tám của hình vuông 619x619 (vì điểm bắt đầu khác bằng cách quay và phản xạ) và sau đó là mọi điểm khác từ phần còn lại của hình vuông.

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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.