Menghitung polistrip

18

Polystrips adalah subset dari polyomino yang sesuai dengan aturan berikut:

  • masing-masing bagian terdiri dari 1 atau lebih sel
  • tidak ada sel yang dapat memiliki lebih dari dua tetangga
  • sel-sel seharusnya tidak menutup lubang

Polyomino bebas berbeda ketika tidak ada transformasi kaku (terjemahan, rotasi, refleksi atau glide refleksi) dari yang lain (potongan yang dapat diambil dan dibalik). Menerjemahkan, memutar, memantulkan, atau meluncur yang mencerminkan polyomino gratis tidak mengubah bentuknya ( Wikipedia )

Misalnya, ada 30 heptastrip gratis (polistrip dengan panjang 7). Berikut semuanya, dikemas dalam kisi 14x15.

Heptastrips

Kredit gambar: Miroslav Vicher

Tujuan

Tulis program / fungsi yang mengambil bilangan bulat positif nsebagai input dan menghitung n-polistrip bebas yang berbeda .

  • n = 1 -> 1 (Satu kotak)

  • n = 2 -> 1 (Hanya ada satu kemungkinan 2-polystrip yang terbuat dari 2 kotak)

  • n = 3 -> 2 (Satu terdiri dari 3 kotak bergabung dalam satu garis dan yang lainnya berbentuk L)

  • n = 4 -> 3 (Satu lurus, satu berbentuk L dan satu berbentuk Z)

  • . . .

Kasus uji:

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

Mencetak gol

Ini , jadi kode yang lebih pendek lebih baik. Saya akan sangat menghargai penjelasan rinci tentang algoritma dan kodenya.

Implementasi referensi parsial dalam J

Saya memutuskan untuk menggambarkan setiap bagian dalam format "vektor" dan saya hanya perlu n-2 blok untuk menggambarkan bagian n-polystrip (hanya ada 1 2-polystrip dan dikembalikan secara eksplisit). Blok menggambarkan arah relatif: 0 - tidak ada perubahan; 1 - belok kiri; 2 - belok kanan. Tidak masalah ke arah mana seseorang akan mulai tetapi hanya untuk menunjukkan di mana sel selanjutnya akan diletakkan. Bisa ada jumlah 0s berurutan, tetapi 1s dan 2s selalu tunggal. Implementasi ini parsial, karena tidak memperhitungkan lubang - solusi untuk n> 6 juga menghitung bagian yang berlubang.

Cobalah online!

Galen Ivanov
sumber
1
OEIS yang relevan. (Tapi tidak mengecualikan lubang.)
Martin Ender
@ Martin Ender Terima kasih, saya tidak tahu.
Galen Ivanov
2
Hanya untuk memastikan, saya berasumsi bahwa jika Anda mengisi kotak 3x3 kecuali untuk pusat dan satu sudut yang juga dianggap sebagai lubang ( 101010dalam notasi sampel Anda)?
Ton Hospel
@Ton Hospel Ya, persis - ini adalah satu-satunya potongan heptastrip yang berlubang.
Galen Ivanov
1
Mungkin pertanyaan yang bagus untuk matematika. SE
Yunus

Jawaban:

12

Python 3 , 480 433 406 364 309 299 295 byte

Tampak seperti titik yang baik untuk memulai karir PPCG saya (atau tidak?).

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)

Cobalah online!

Suntingan:

  • Diseret Ddan X, dan tweak sedikit di beberapa tempat golf.
  • Menerapkan lebih banyak trik, terutama yang berhubungan dengan set.
  • Diubah menjadi bentuk program, dan diubah menjadi menggunakan bilangan kompleks alih-alih angka acak m. (Bilangan kompleks benar-benar fitur golfy yang kuat tetapi sering diabaikan; diadaptasi dari solusi xnor untuk tantangan lain )
  • Mengubah LFRrepresentasi string menjadi -1,0,1tupel dan mengorbankan waktu eksekusi untuk jumlah byte byte yang dikurangi (!). Sekarang solusinya secara teoritis benar tetapi batas waktu sebelum menghasilkan hasilnya selama 15.
  • Satu-baris terima kasih kepada Jonathan Frech, maka saya menemukan alternatif yang jauh lebih baik untuk menghitung r. AKHIRNYA DI BAWAH 300 HASIL !!!
  • Anehnya 1jdapat menempel pada hal lain tanpa membingungkan parser (-2B), dan notmemiliki prioritas yang sangat rendah (-2B).

Versi usang (480 byte):

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

Cobalah online!

Solusi yang tidak digabungkan dengan komentar:

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

Cobalah online!

m = 999dipilih karena butuh waktu eksponensial untuk menghitung semuanya, dan sudah butuh ~ 8s untuk menghitung n = 1..15. Mungkin tidak apa-apa untuk menyimpan 1 byte dengan menggunakan 99 sebagai gantinya. Kami tidak membutuhkan ini lagi, dan sekarang dijamin benar untuk ukuran input sewenang-wenang, berkat bilangan kompleks bawaan.

Bubbler
sumber
5
Selamat datang di PPCG! Jelas cara yang mengesankan untuk memulai karir PPCG Anda. :)
Martin Ender
3
Selamat datang di PPCG dan terima kasih atas solusi ini! Saya sudah menyerah berharap untuk melihat solusi :)
Galen Ivanov
3
Tampak seperti titik yang baik untuk memulai karir PPCG saya (atau tidak?) . Nah, ini adalah solusi yang sangat singkat untuk hal ini yang sebagian besar dari kita bahkan tidak pernah berpikir bisa melakukannya, bahkan versi yang tidak diklik terlihat sangat sederhana, tetapi, eh, mungkin ini adalah cara rata-rata untuk memulai karir PPCG Anda, kan? :)
Erik the Outgolfer
1
@Erik Kalimat itu setengah lelucon :) Tapi ya, solusinya bahkan mengejutkan bagi saya - saya tidak pernah berharap diri untuk menarik ~ pengurangan 36% dari pengajuan asli.
Bubbler
1
Kemungkinan 303 byte .
Jonathan Frech
4

APL (Dyalog Unicode) , 70 65 byte

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

Cobalah online!

Versi program lengkap dari kode di bawah ini, terima kasih kepada Adám.


APL (Dyalog Unicode) , 70 byte

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

Cobalah online!

Bagaimana itu bekerja

Kode di atas setara dengan definisi berikut:

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

Ini berfungsi seperti solusi Python, tetapi dalam urutan yang berbeda. Itu genmenghapus LFR-garis panjang n-2, canonicalizes setiap strip, mengambil strip nique, tests setiap strip jika menyentuh sendiri (1 jika tidak menyentuh, 0 sebaliknya), dan menjumlahkan +/hasil boolean.

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)
Bubbler
sumber
-5
Adem