最悪の場合のマンハッタンの除外


20

想像してWによるHのトロイダル状ラップの正方形のグリッドを。アイテムは次のようにグリッドに配置されます。

最初のアイテムは任意の正方形に配置できますが、後続のアイテムは前のアイテムのマンハッタン距離 R範囲Rのフォンノイマン近傍とも呼ばれます)内に配置することはできません。慎重に位置を選択すると、有効な位置がなくなる前に多数のアイテムをグリッドに合わせることができます。ただし、代わりに反対の目的を検討してください。配置できるアイテムの最小数はいくらですか?

以下は、半径5の除外ゾーンです。

半径5除外ゾーン

ここに別の半径5の除外ゾーンがあります。今回はエッジに近いため、ラッピングの動作が明らかです。

ラッピング半径5の除外ゾーン

入力

3つの整数:

  • W:グリッドの幅(正の整数)
  • H:グリッドの高さ(正の整数)
  • R:除外ゾーンの半径(非負の整数)

出力

整数N。これは、配置できるアイテムの最小数であり、それ以上の有効な配置を妨げます。

詳細

  • 半径がゼロの場合、除外ゾーンは1平方(アイテムが配置されたゾーン)になります。
  • Nの半径は、N直交ステップで到達できるゾーンを除外します(エッジがトロイド状にラップすることを思い出してください)。

あなたのコードは、R = 0の些細なケースで機能する必要がありますが、W = 0またはH = 0で機能する必要はありません。

コードでは、R > WまたはR > Hの場合も処理する必要があります。

制限時間とテストケース

コードはすべてのテストケースを処理できなければならず、各テストケースは5分以内に完了する必要があります。これは簡単なはずです(JavaScriptソリューションの例では、テストケースごとに数秒かかります)。時間制限は、主に極端なブルートフォースアプローチを除外することです。例のアプローチは、まだかなり強引です。

コードが1台のマシンで5分以内に完了しても、十分に近い別のマシンでは完了しない場合。

フォーム入力のテストケース:出力としてW H R : N

5 4 4 : 1
5 4 3 : 2
5 4 2 : 2
5 4 1 : 5

7 5 5 : 1
7 5 4 : 2
7 5 3 : 2
7 5 2 : 4

8 8 8 : 1
8 8 7 : 2
8 8 6 : 2
8 8 5 : 2
8 8 4 : 2
8 8 3 : 4

 7  6  4 : 2
 7  6  2 : 4
11  7  4 : 3
11  9  4 : 4
13 13  6 : 3
11 11  5 : 3
15 14  7 : 2
16 16  8 : 2

視覚化を支援し、アイデアをいじるのに役立つスニペット

例(変更されていない)ソリューション

小さな出力の例(半径は幅と高さよりも小さくないため)。テストケースのいずれかを処理できますが、タイムアウトし、ほとんどの大規模なケースをあきらめます。


4
素晴らしいコードスニペット!
ストレッチマニアック

@StretchManiacありがとう:)私はJavaScriptを学ぼうとしているので、どんなフィードバックでも歓迎です
-trichoplax

1
それはかなりいいスニペットです。私もその配色が好きです。パレットからですか?
マイル

@milesありがとう-色は推測された後、少し微調整されます(しかし、それほど多くはありません-それらはまだ6ではなく3文字のカラーコードです)。スニペットコードの行の3番目のブロックで使用されている色を確認できます。
-trichoplax

回答:


5

Python 2、216 182バイト

def f(W,H,R):L={(i%W,i/W)for i in range(W*H)};M={(x,y)for x,y in L if min(x,W-x)+min(y,H-y)>R};g=lambda s:min([1+g(s-{((a+x)%W,(b+y)%H)for x,y in L-M})for a,b in s]or[1]);return g(M)

のように入力しf(16,16,8)ます。@trichoplaxのsampleとほとんど同じアルゴリズムを使用しますが、セットを使用します。最初は、最初のアイテムをに配置しませんでした(0, 0)が、これにより最後のいくつかのケースで窒息しました。

上記のすべてのケースは10秒以内に完了し、十分に制限されています。実際、ケースは十分に小さいため、効率を下げる余地が少しあるため、重複した状態をチェックするチェックを削除できます。

(ゴルフの手助けをしてくれた@trichoplaxに感謝)

拡張:

def f(W,H,R):
  # All cells
  L={(i%W,i/W)for i in range(W*H)}                 

  # Mask: Complement of exclusion zone around (0, 0) 
  M={(x,y)for x,y in L if min(x,W-x)+min(y,H-y)>R}

  # Place recursively
  g=lambda s:min([1+g(s-{((a+x)%W,(b+y)%H)for x,y in L-M})for a,b in s]or[1])
  return g(M)

2

Pythonの3、270 262 260 251 246 226

(Sp3000に感謝します:

  • -~ の代わりに +1最後の行の スペースを失うことができますreturn
  • 余計な括弧を失います W*H
  • ラムダ...
  • すべてを1行に配置します。
  • python modulo %は負の数に対して正の結果を与え、さらに20バイトを節約します)

これは、Python 3に移植された質問からのJavaScriptの回答例です。

あまりにも多くの関数引数を渡す必要を避けるために、2つのサポート関数を計算関数内に移動して、スコープを共有するようにしました。また、インデントのコストを回避するために、これらの各関数を1行にまとめました。

説明

このかなり強引なアプローチでは、最初のアイテムを(0、0)に配置し、除外されたすべての正方形をマークします。次に、すべての正方形が除外されるまで、残りのすべての有効な正方形にアイテムを再帰的に配置し、必要なアイテムの最小数を返します。

ゴルフコード:

def C(W,H,R):r=range;M=lambda g:min([M(G(g,x,y))for x in r(W)for y in r(H)if g[x+W*y]]or[-1])+1;G=lambda g,x,y:[g[a+W*b]if min((x-a)%W,(a-x)%W)+min((y-b)%H,(b-y)%H)>R else 0for b in r(H)for a in r(W)];return-~M(G([1]*W*H,0,0))

未ゴルフコード:

def calculate(W, H, R):
    starting_min = W * H + 1
    cells = [0] * (W * H)
    grid_state = grid_with_item_added(cells, 0, 0, W, H, R)
    return min_from_here(grid_state, starting_min, W, H, R) + 1

def min_from_here(grid_state, starting_min, W, H, R):
    no_cells = True
    min = starting_min
    for x in range(W):
        for y in range(H):
            if grid_state[x + W * y] == 0:
                no_cells = False
                new_grid_state = grid_with_item_added(grid_state, x, y, W, H, R)
                m = min_from_here(new_grid_state, starting_min, W, H, R)
                if m < min:
                    min = m

    if no_cells:
        return 0
    else:
        return min + 1

def grid_with_item_added(grid_state, x, y, W, H, R):
    grid = grid_state[:]
    for a in range(W):
        for b in range(H):
            if manhattan_distance(a, b, x, y, W, H) <= R:
                grid[a + W * b] = 1

    return grid

def manhattan_distance(a, b, c, d, W, H):
    horizontal = min(abs(W + c - a) % W, abs(W + a - c) % W)
    vertical = min(abs(H + d - b) % H, abs(H + b - d) % H)
    return horizontal + vertical


if __name__ == '__main__':
    import sys
    arguments = sys.argv[1:]
    if len(arguments) < 3:
        print('3 arguments required: width, height and radius')
    else:
        print(calculate(int(arguments[0]), int(arguments[1]), int(arguments[2])))

改変されていないコードは関数を定義し、コマンドラインから呼び出せるようにするコードも含んでいます。ゴルフコードは単に関数を定義するだけで、標準コードのゴルフの質問に十分です

コマンドラインからゴルフのコードをテストする場合は、コマンドラインの処理が含まれています(ただし、ゴルフではありません)。

コマンドラインでテスト可能なゴルフコード

def C(W,H,R):r=range;M=lambda g:min([M(G(g,x,y))for x in r(W)for y in r(H)if g[x+W*y]]or[-1])+1;G=lambda g,x,y:[g[a+W*b]if min((x-a)%W,(a-x)%W)+min((y-b)%H,(b-y)%H)>R else 0for b in r(H)for a in r(W)];return-~M(G([1]*W*H,0,0))

if __name__ == '__main__':
    import sys
    arguments = sys.argv[1:]
    if len(arguments) < 3:
        print('3 arguments required: width, height and radius')
    else:
        print(C(int(arguments[0]), int(arguments[1]), int(arguments[2])))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.