ポリストリップのカウント


18

ポリストリップは、次のルールに準拠したポリオミノのサブセットです。

  • 各ピースは1つ以上のセルで構成されます
  • セルに3つ以上の隣接セルを含めることはできません
  • セルは穴を囲むべきではありません

自由なポリオミノは、他のもの(拾い上げたりひっくり返したりできる部分)の厳密な変換(平行移動、回転、反射、またはグライド反射)がない場合に区別されます。無料のポリオミノを平行移動、回転、反射、またはグライド反射してもその形状は変わりません(ウィキペディア

たとえば、30個の無料のヘプタストリップ(長さ7のポリストリップ)があります。これらはすべて、14x15のグリッドにまとめられています。

ヘプタストリップ

画像クレジット:Miroslav Vicher

ゴール

n入力として正の整数を取り、個別のフリーnポリストリップを列挙するプログラム/関数を作成します。

  • n = 1-> 1(単一の正方形)

  • n = 2-> 1(2つの正方形で作られた2つのポリストリップが1つだけあります)

  • n = 3-> 2(1つは3つの正方形が直線で結合され、もう1つはL字型です)

  • n = 4-> 3(1つの直線、1つのL字型、1つのZ字型)

  • 。。。

テストケース:

n   polystrips

1   1
2   1
3   2
4   3
5   7
6   13
7   30
8   64
9   150
10  338
11  794
12  1836
13  4313
14  10067
15  23621

得点

これはであるため、短いコードの方が優れています。アルゴリズムとコードの詳細な説明をいただければ幸いです。

Jでの部分参照実装

各部分を「ベクター」形式で記述することにしました。nポリストリップの部分を記述するために必要なのはn-2ブロックだけです(2ポリストリップは1つだけで、明示的に返されます)。ブロックは相対的な方向を表します:0-変更なし。1-左折します。2-右折します。どの方向から開始するかは関係ありませんが、次のセルをどこに配置するかを示すだけです。連続する0はいくつあってもかまいませんが、1と2は常に単一です。この実装は部分的なものです。これは、穴を考慮していないためです。n> 6のソリューションでは穴のある部分もカウントされます。

オンラインでお試しください!


1
関連するOEIS。(ただし、穴を除外しません。)
マーティンエンダー

@ Martin Enderありがとう、私はそれを知りませんでした。
ガレンイワノフ

2
念のため、中心と穴としてもカウントされる1つのコーナー(101010サンプル表記)を除いて3x3グリッドを埋めると仮定しますか?
トンホスペル

@Ton Hospelはい、正確に-これは穴のある唯一のヘプタストリップです。
ガレンイワノフ

1
math.SEの良い質問かもしれません
ジョナ

回答:


12

Pythonの3480の 433 406 364 309 299 295バイト

私のPPCGキャリアを始めるのに良いポイントのように見えました(そうではないのですか?)。

def C(s):
 S,*a={''},0,1;n=d=r=1
 for c in s:d=c*d*1jor d;n+=d;a+=n,;r*=not{n}&S;x,*a=a;S|={x+t+u*1jfor t in A for u in A}
 return r
from itertools import*;A=-1,0,1;n,y=int(input())-2,0;x={*filter(C,product(*[A]*n))}
while x:s=x.pop();S=*(-u for u in s),;x-={s[::-1],S,S[::-1]}-{s};y+=1
print(y)

オンラインでお試しください!

編集:

  • インラインDおよびX、そしていくつかのゴルフ可能な場所で少し調整しました。
  • 主にセット関連のものより多くのトリックを適用しました。
  • プログラム形式に変更され、任意の数値ではなく複素数を使用するように変更されましたm。(複雑な数値は本当に強力ですが、しばしばゴルフの機能を無視します。xnorのソリューションから別の課題に適応します)
  • LFR文字列表現を-1,0,1タプルに変更し、非常に多くのバイト削減のために実行時間を犠牲にしました(!)。解決策は理論的には正しいですが、15の結果を出力する前にタイムアウトします。
  • Jonathan Frechのおかげでループが一列に並んでいたので、計算のためのはるかに優れた代替案が見つかりましたr。最終的に300バイト未満!!!
  • 驚いたことに1j、パーサーを混乱させることなく他のものに固執することができ(-2B)、not非常に低い優先順位を持っています(-2B)。

旧バージョン(480バイト):

def C(s):
 m=999;a=[0,1];n=d=1
 D={'F':{},'L':{1:m,m:-1,-1:-m,-m:1},'R':{1:-m,-m:-1,-1:m,m:1}}
 X=lambda x:{x+~m,x-m,x-m+1,x-1,x,x+1,x+m-1,x+m,x-~m}
 for c in s:
  d=D[c].get(d,d);n+=d;a+=n,
  if n in set().union(*map(X,a[:-3])):return 0
 return 1
def f(n):
 if n<3:return 1
 x={*'LF'}
 for _ in range(3,n):x={s+c for s in x for c in({*'LRF'}-{s[-1]})|{'F'}}
 y={*x}
 for s in x:
  if s in y:S=s.translate(str.maketrans('LR','RL'));y-={s[::-1],S,S[::-1]}-{s}
 return sum(map(C,y))

オンラインでお試しください!

コメント付きのゴルフのないソリューション:

t = str.maketrans('LR','RL')

# hole checking function
def check(s):
    m = 999   # (imaginary) board size enough to fit all generated polyominoes
    a = [0,1] # previous path
    n = 1     # current cell
    d = 1     # current direction
    # dict for direction change
    D = {'F':{}, 'L':{1:m, m:-1, -1:-m, -m:1}, 'R':{1:-m, -m:-1, -1:m, m:1}}
    # used to 'blur' all cells in path into 3x3
    X = lambda x: {x-m-1,x-m,x-m+1,x-1,x,x+1,x+m-1,x+m,x+m+1}
    for c in s:
        d = D[c].get(d,d) # change direction
        n += d            # move current cell
        # the polyomino has a hole if the current cell touches previous cells (including diagonally; thus the blurring function)
        if n in set().union(*map(X,a[:-2])): return False
        a.append(n)       # add current cell to the path
    return True

# main function
def f(n):
    if n < 3: return 1
    x = {*'LF'}
    # generate all polystrips using the notation similar to the reference
    for _ in range(3, n): x = {s+c for s in x for c in ({*'LRF'}-{s[-1]})|{'F'}}
    y = {*x}
    # remove duplicates (mirror, head-to-tail, mirror of head-to-tail) but retain self
    for s in x:
        if s in y:
            S = s.translate(t)
            y -= {s[::-1], S, S[::-1]} - {s}
    # finally filter out holey ones
    return sum(map(check,y))

オンラインでお試しください!

m = 999すべてを数えるのに指数関数的な時間がかかり、計算にすでに〜8秒かかっているためn = 1..15です。代わりに99を使用して1バイトを保存しても問題ないでしょう。これはもう必要ありませんが、組み込みの複素数のおかげで、任意の入力サイズに対して正しいことが保証されています。


5
PPCGへようこそ!PPCGのキャリアを始めるための、間違いなく印象的な方法です。:)
マーティンエンダー

3
PPCGへようこそ。このソリューションに感謝します。私はすでに解決策を見ることをあきらめていました:)
ガレンイワノフ

3
私のPPCGキャリアを始めるのに良いポイントのように見えました(そうでないのですか?)まあ、これは私たちのほとんどがこれまでに考えたこともないほど驚くほど短い解決策であり、未ゴルフバージョンでも驚くほどシンプルに見えますが、ええ、これはあなたのPPCGキャリアを開始する平均的な方法でしょうか?:)
エリック・ザ・アウトゴルファー

1
@Erikその行は冗談の半分でした:)しかし、ええ、解決策は私にとっても驚くべきことです -元の提出から最大36%の削減を引き出すことは決して期待していませんでした。
バブラー


4

APL(Dyalog Unicode)70 65バイト

+/{∧/2≤|(⊢-¯3↓¨,\)+\0 1\0j1*⍵}¨∪{(⊃∘⍋⊃⊢)(⊢,⌽¨)⍵(-⍵)}¨2-,⍳2↓⎕⍴3

オンラインでお試しください!

Adámのおかげで、以下のコードの完全なプログラムバージョンです。


APL(Dyalog Unicode)、70バイト

{+/{∧/2≤|(⊢-¯3↓¨,\)+\0 1\0j1*⍵}¨∪{(⊃∘⍋⊃⊢)(⊢,⌽¨)⍵(-⍵)}¨2-,⍳3⍴⍨0⌈⍵-2}

オンラインでお試しください!

使い方

上記のコードは、次の定義と同等です。

gen←{2-,⍳3⍴⍨0⌈⍵-2}
canonicalize←{(⊃∘⍋⊃⊢)(⊢,⌽¨)⍵(-⍵)}
test←{(∧/⊢{∧/2≤|⍺-¯3↓⍵}¨,\)+\0 1\0j1*⍵}
{+/test¨∪canonicalize¨gen⍵}

これはPythonソリューションと同様に機能しますが、順序は異なります。これはgenerates LFR長さの-stripsをn-2canonicalize各ストリップをだ、かかるniqueストリップを、testそれ自体に触れると、各ストリップS(1接触していない場合は、そうでなければ0)、及び加算+/ブール結果を。

gen

{2-,⍳3⍴⍨0⌈⍵-2}
{            }   ⍵←input number n
        0⌈⍵-2    xmax(0, n-2)
     3⍴⍨         x copies of 3
   ,⍳            multi-dimensional indexes; x-th cartesian power of [1,2,3]
                 (`⍳` gives x-dimensional hypercube; `,` flattens it)
 2-              compute 2-k for each k in the array

 in each strip, ¯1, 0, 1 corresponds to R, F, L respectively

canonicalize

{(⊃∘⍋⊃⊢)(⊢,⌽¨)⍵(-⍵)}
{                  }   ⍵←single strip
              ⍵(-⍵)    nested array of  and its LR-flip
        (⊢,⌽¨)         concatenate their head-to-tail flips to the above
 (⊃∘⍋  )               find the index of the lexicographically smallest item
     ⊃⊢                take that item

test

{(∧/⊢{∧/2≤|⍺-¯3↓⍵}¨,\)+\0 1\0j1*⍵}
{                                  }   ⍵←single strip
                              0j1*⍵    power of i; direction changes
                            ×\         cumulative product; directions
                        0 1,     initial position(0) and direction(1)
                      +\         cumulative sum; tile locations
 (  ⊢{           }¨,\)    test with current tile(⍺) and all tiles up to ⍺(⍵):
             ¯3↓⍵         x←⍵ with last 3 tiles removed
           ⍺-             relative position of each tile of x from 
        2≤|               test if each tile of x is at least 2 units away
      ∧/                  all(...for each tile in x)
  ∧/         all(...for each position in the strip)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.