一意に分離されたピクセル


30

以下のためにNによってN画像、全く分離距離が複数回存在しないように、ピクセルのセットを見つけます。つまり、2つのピクセルが距離dで区切られている場合、それらは正確にdで区切られている唯一の2つのピクセルです(ユークリッド距離を使用)。dは整数である必要はないことに注意してください。

課題は、他の誰よりも大きなセットを見つけることです。

仕様

入力は必要ありません-このコンテストのNは619に修正されます。

(人々は尋ね続けているので、番号619について特別なことは何もありません。最適な解決策を考えにくいほど大きく、Stack Exchangeが自動的に縮小することなくN x Nの画像を表示できるほど小さいように選択されました。最大630 x 630のフルサイズを表示し、それを超えない最大の素数で行くことにしました。)

出力は、スペースで区切られた整数のリストです。

出力の各整数は、ピクセルの1つを表し、0から英語の読み取り順序で番号が付けられます。たとえば、N = 3の場合、位置は次の順序で番号が付けられます。

0 1 2
3 4 5
6 7 8

必要に応じて、実行中に進行状況情報を出力できますが、最終的なスコアリング出力が簡単に入手できる限りです。STDOUTまたはファイル、または下のStack Snippet Judgeに貼り付けるのに最も簡単なものに出力できます。

N = 3

選択した座標:

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

出力:

0 1 5

勝ち

スコアは、出力内の場所の数です。最も高いスコアを持つ有効な回答のうち、そのスコアで最も早く投稿を出力します。

コードは確定的である必要はありません。最高の出力を投稿できます。


研究の関連分野

(ゴロムのリンクについてはAbulafiaに感謝します)

これらはどちらもこの問題と同じではありませんが、どちらも概念が似ており、これにアプローチする方法についてのアイデアを提供します。

この質問に必要なポイントは、ゴロム長方形と同じ要件の対象ではないことに注意してください。ゴロム長方形は、各点から互いへのベクトルが一意であることを要求することにより、1次元のケースから拡張されます。これは、水平方向に2の距離で分離された2つのポイントと、垂直方向に2の距離で分離された2つのポイントが存在できることを意味します。

この質問の場合、一意でなければならないのはスカラー距離です。したがって、水平と垂直の2の分離はありません。この質問に対するすべての解はゴロム長方形になりますが、すべてのゴロム長方形がこの質問。


上限

Dennisはチャットで487がスコアの上限であることを有益に指摘し、証拠を示しました。

私のCJamコード(619,2m*{2f#:+}%_&,)によれば、0〜618 (両方を含む)の2つの整数の2乗の合計として記述できる118800個の一意の番号があります。nピクセルには、互いにn(n-1)/ 2個の一意の距離が必要です。n = 488の場合、118828になります。

そのため、画像内のすべての潜在的なピクセル間に118,800の異なる長さがあり、488個の黒ピクセルを配置すると118,828の長さになり、すべてを一意にすることができなくなります。

誰かがこれより低い上限の証拠を持っているかどうか聞いて非常に興味があります。


リーダーボード

(各ユーザーによるベストアンサー)

リーダーボード画像


スタックスニペットジャッジ


私はここでPietの答えを見てみたいと思います
-C5H8NNaO4

@ C5H8NNaO4競争はオープンエンドです-誰も最適なソリューションの近くにいないので、新しい答えの余地が十分にあります
...-trichoplax

証明済みのピクセルのリストと実験的なピクセルのリストの両方に賞金を提供しているので、この問題に何らかのアプリケーションがあると思いますか?
15

気づいていないことを@Fatalizeしますが、それを聞いて魅了されるでしょう。同様の問題であるコスタスアレイには実用的なアプリケーションがリストされていますが、この特定の問題については何も見つかりませんでした。
-trichoplax

1
私はこれを見てきましたが、n = 487がピクセルの最小の上限であると信じています。好奇心から、賞金の下限に限界がないという証拠を受け入れますか?
メゴ

回答:


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を持っています(ただし、これには多くの調整と異なる初期ポイントの試行が必要でした)。

ここに画像の説明を入力してください

コード

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-Prolog、スコア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ポイント


理論上の最大値は487であるため、増分の増加であっても重要です
...-trichoplax

表示されている出力はStack Snippetで機能しましたか?(例の回答のように)スペースで区切って指定しましたが、その主な理由は、スタックスニペットが機能するようにするためでした。
-trichoplax

@trichoplaxええ、タイプミスです。ピクセル0から始めて、修正します。画像を取得するには、2つの角括弧の間の出力部分を選択し、すべてのコンマを削除しました。ただし、Stackスニペットはコンマ区切りのピクセルで機能するようです。
15

4

Haskell- 115 130 131 135 136

私のインスピレーションは、エラトステネスのふるいであり、特にエラトステネスの本物のふるい、ハーヴェイマッドカレッジのメリッサE.オニールによる論文でした。私の元のバージョン(インデックス順でポイントを考慮)はポイントを非常に迅速にふるいましたが、何らかの理由で、このバージョンでポイントをシャッフルする前にシャッフルすることにしたことを思い出せませんランダムジェネレーターの新しいシード)。ポイントの順序が変わっていないため、実際にはふるいにかけられていないため、この単一の115ポイントの回答を作成するのに数分かかります。Vectorおそらく今はノックアウトがより良い選択でしょう。

したがって、このバージョンをチェックポイントとして使用すると、「Genuine Sieve」アルゴリズムに戻り、選択のためにListモナドを活用するか、またはSet同等の操作を交換しVectorます。

編集:だから、私はふるいアルゴリズムに戻り、「倍数」の生成を改善しました(半径が任意の2点間の距離に等しい円上の整数座標で点を見つけることでインデックスをノックし、素数の倍数を生成します) )いくつかの不必要な再計算を回避することにより、いくつかの一定時間の改善を行う

何らかの理由で、プロファイリングを有効にして再コンパイルすることはできませんが、現在の主要なボトルネックはバックトラックであると考えています。少しの並列性と同時実行性を調べると線形のスピードアップが得られると思いますが、メモリを使い果たすとおそらく2倍の改善になります。

編集:バージョン3は少し曲がりくねっていましたが、最初に(以前の選択肢からふるい分けた後)次の𝐧インデックスを取得し、次の最小ノックアウトセットを生成するインデックスを選択するヒューリスティックを試しました。これは結局非常に遅いので、私は全探索空間のブルートフォースメソッドに戻りました。いくつかの原点からの距離でポイントを並べるというアイデアが浮かび、1つのポイント(私の忍耐が続く時間)で改善することになりました。このバージョンでは、インデックス0が原点として選択されるため、平面の中心点を試す価値があります。

編集:サーチスペースを並べ替えて、中心から最も遠いポイントに優先順位を付けて、4ポイントをピックアップしました。私のコードをテストしている場合、135 136は実際に見つかった2番目、3番目のソリューションです。高速編集:このバージョンは、実行したままにしておくと生産性を維持する可能性が最も高いようです。私は137で引き分け、138を待つ忍耐が尽きるのではないかと思います。

私が気づいたことの1つ(誰かに役立つかもしれません)は、平面の中心から点の順序を設定する(つまり、(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時間かかります。いずれに
せよ

私はその目標を達成する可能性は低いようですが、私はまだ137要素セットを生成することができていません。この方法はおそらくタップされていると思う
RB

興味深いのは、アプローチが異なる2つの異なる答えが、同じサイズで最大値に達していることです。
-trichoplax

上限はおそらくかなり近いと思います。無限平面と任意の2点を考えます。任意の距離でのこれらのポイントの最適な配置は、選択された両方のポイントの中心を持つd半径の円をトレースすることにより、考慮から除外される他のポイントの数を最小限にします。d円)、および整数座標を交差しない垂直二等分線。そのため、新しいポイントごとに他のポイントが考慮からn+1除外さ6nれます(最適な選択を使用)。
RB

3

Python 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

スタックスニペットからの画像

129個の一意に分離されたピクセルの画像


3

Python 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

Scala、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

Python、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 247831281 2972​​8 33436 6863 37767 26665 14297 4402 43363 50 113313 88637 122569 11956 36098 79401 61471 135610 31796 4570 150418 57797 4581 125201 151128 115936 165898 127697 162290 33091 20098 189414 187620 186440 91290 206766 35619 69033 351 186511 129058 228458 69065 226046 278 28276 276 28276 276925 235925 164324 18967 254416 970 249115 21544 95185 231226 54354 104483 280665 518 147181 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

好奇心の強い人のために、ここにいくつかのブルートフォースの小さなNを示します。

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の両方で実行します。cpythonの方が速い場合は、pypyでチケットを提出します。この特定のケースでは、pypyはかなり速くはCPythonよりも、それは私がこれらの番号:)得た方法です
ウィル

興味がありますが、「迅速」には何が必要ですか?
カイン

「迅速」@Cain IIRC 5分程度だった
ウィル

2

ファントム96

私は進化アルゴリズムを使用し、基本的に一度にk個のランダムポイントを追加し、j個の異なるランダムセットに対してそれを行い、最適なポイントを選択して繰り返します。現時点ではかなりひどい答えですが、速度のために1世代あたり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
ああ、すごい、ごめんなさい。うーん、私がテストしたとき、それのすべてを早くコピーしたに違いない。私は何が起こっているかを修正し、更新で応答します
カイン

ああ、私はそれを理解しました、新しいピクセルを追加するとき、私はそれが他の2つのピクセルから等距離ではないことを確認していませんでした
カイン

それを修正しましたが、今は本当にひどいです、私は誤って最良のソリューションではなく最悪のソリューションを見つけるかもしれないと思う
カイン

少なくとも現在は動作しているので、パラメーターを調整して結果を改善できるかどうかを確認できます。別の新しいアプローチを見るのは素晴らしいことです。+1
trichoplax

1

Python 3、119

なぜこの関数に名前を付けたのか思い出せませんmc_uspが、マルコフ連鎖と関係があるのではないかと思います。ここで、PyPyで実行したコードを約7時間公開します。プログラムは、画像内のすべてのピクセルをチェックするまでピクセルをランダムに選択し、最適なセットの1つを返すことにより、100種類のピクセルセットを構築しようとします。

別の注意として、ある時点で、私たちは本当にその上限をN=619488よりも良くすることを試みるべきです。なぜなら、ここでの答えから判断すると、その数は非常に高いからです。すべての新しいポイントが最適な選択でポイントを削除する可能性についてのRowan Blushのコメントは、良いアイデアのように思えました。残念ながら、フォーミュラを調べてみると、ここでポイントをセットに追加した後に削除されるポイントの数は、この考えは最適ではない可能性があります。ときのチェックよりも大きい場合、より大きい有望なようだが、より大きくあると私たちは9が行き、実際の上位であることを証明してきました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)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.