Polystriplerin sayılması


18

Polystripler, aşağıdaki kurallara uyan bir polimino alt kümesidir:

  • her parça 1 veya daha fazla hücreden oluşur
  • hiçbir hücrede ikiden fazla komşu olamaz
  • hücreler bir deliği kapatmamalıdır

Serbest polimomlar, hiçbiri bir başkasının (toplanıp çevrilebilen parçalar) katı bir dönüşümü (çeviri, döndürme, yansıma veya kayma yansıması) olmadığında farklıdır. Serbest bir poliominoyu yansıtan çeviri, döndürme, yansıtma veya kayma şeklini değiştirmez ( Wikipedia )

Örneğin, 30 serbest heptastrip (uzunluğu 7 olan polystripler) vardır. Hepsi 14x15 ızgaraya yerleştirilmiş.

Heptastrips

Fotoğraf kredisi: Miroslav Vicher

Hedef

nGirdi olarak pozitif bir tamsayı alan ve farklı serbest n-polystripleri numaralandıran bir program / fonksiyon yazın .

  • n = 1 -> 1 (Tek kare)

  • n = 2 -> 1 (2 kareden oluşan sadece bir olası 2-polystrip vardır)

  • n = 3 -> 2 (Biri bir hatta birleştirilen 3 kareden oluşur ve diğeri L şeklindedir)

  • n = 4 -> 3 (Bir düz, bir L şeklinde ve bir Z şeklinde)

  • . . .

Test senaryoları:

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

puanlama

Bu , bu yüzden daha kısa kod daha iyidir. Algoritmanın ve kodun ayrıntılı açıklamalarını çok takdir ediyorum.

J'de kısmi referans uygulaması

Her parçayı "vektör" formatında tanımlamaya karar verdim ve n-polystrip parçasını tanımlamak için sadece n-2 bloğuna ihtiyacım var (sadece 1 2-polystrip var ve açıkça iade ediliyor). Bloklar göreceli yönü tanımlar: 0 - değişiklik yok; 1 - sola dönün; 2 - sağa dönün. Hangi yönün başlayacağı önemli değil, sadece bir sonraki hücrenin nereye konulacağını belirtmek. Herhangi bir sayıda ardışık 0 olabilir, ancak 1'ler ve 2'ler her zaman bekar. Bu uygulama kısadır, çünkü delikleri hesaba katmaz - n> 6 için çözümler delikli parçaları da sayar.

Çevrimiçi deneyin!


1
İlgili OEIS. (Ancak delikleri hariç tutmaz.)
Martin Ender

@ Martin Ender Teşekkür ederim, bilmiyordum.
Galen Ivanov

2
Sadece emin olmak için, merkez ve aynı zamanda bir delik olarak da sayılan bir 3x3 ızgarası doldurursanız ( 101010örnek gösteriminizde) olduğunu varsayalım ?
Ton Hospel

@Ton Hospel Evet, tam olarak - bu delikli tek heptastrip parçası.
Galen Ivanov

1
Belki de matematik için iyi bir soru. SE
Jonah

Yanıtlar:


12

Python 3 , 480 433 406 364 309 299 295 bayt

PPCG kariyerime başlamak için iyi bir nokta gibi görünüyordu (ya da değil?).

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)

Çevrimiçi deneyin!

Düzenlemeler:

  • Inline Dve Xve bazı golfable noktalar üzerinde biraz tweaked.
  • Daha çok hile, özellikle setle ilgili olanlar uygulandı.
  • Program formuna değiştirildi ve rasgele sayı yerine karmaşık sayılar kullanılarak değiştirildi m. (Karmaşık sayılar gerçekten güçlü ancak çoğu zaman göz ardı edilen bir golf özelliğidir; xnor'un çözümünden başka bir zorluk için uyarlanmıştır )
  • Değişti LFRiçin dize temsilini -1,0,1küpe ve bayt azalma çılgın miktarda kurban yürütme zamanı (!). Şimdi çözüm teorik olarak doğrudur, ancak sonucu 15 için çıkarmadan önce zaman aşımına uğrar.
  • Jonathan Frech sayesinde döngüyü tek sıralı hale getirdim, sonra hesaplamak için çok daha iyi bir alternatif buldum r. Nihayet 300 bayt altında !!!
  • Şaşırtıcı bir şekilde 1j, ayrıştırıcıyı (-2B) karıştırmadan başka bir şeye yapışabilir ve notinanılmaz derecede düşük önceliğe sahiptir (-2B).

Eski sürüm (480 bayt):

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

Çevrimiçi deneyin!

Yorumlar ile çözülmemiş çözüm:

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

Çevrimiçi deneyin!

m = 999seçildi, çünkü her şeyi saymak üstel zaman alıyor ve hesaplanması ~ 8 saniye alıyor n = 1..15. Belki de 99 kullanarak 1 bayt kaydetmek iyidir. Artık buna ihtiyacımız yok ve şimdi yerleşik karmaşık sayı sayesinde keyfi giriş boyutu için doğru olduğu garanti ediliyor.


5
PPCG'ye Hoşgeldiniz! PPCG kariyerinize başlamak için kesinlikle etkileyici bir yol. :)
Martin Ender

3
PPCG'ye hoş geldiniz ve bu çözüm için teşekkürler! Zaten bir çözüm görmeyi beklemekten vazgeçmiştim :)
Galen Ivanov

3
PPCG kariyerime başlamak için iyi bir nokta gibi görünüyordu (ya da değil?) . Pekala, bu, çoğumuzun asla düşünemeyeceğini bile düşünemediğimiz şaşırtıcı derecede kısa bir çözüm, ungolfed versiyon bile şaşırtıcı derecede basit görünüyor, ama, belki, bu PPCG kariyerinize başlamak için ortalama bir yol, değil mi? :)
Outgolfer Erik

1
@Erik Bu çizgi bir şakaydı :) Ama evet, çözüm benim için bile şaşırtıcı - kendimden orijinal gönderime göre ~% 36 indirim yapmamı beklemiyordum.
Bubbler


4

APL (Dyalog Unicode) , 70 65 bayt

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

Çevrimiçi deneyin!

Adám sayesinde aşağıdaki kodun tam program sürümü.


APL (Dyalog Unicode) , 70 bayt

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

Çevrimiçi deneyin!

Nasıl çalışır

Yukarıdaki kod aşağıdaki tanıma eşdeğerdir:

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

Bu, Python çözümü gibi çalışır, ancak farklı bir sırayla. Bu generates LFRuzunluğunun -strips n-2, canonicalizeher şeridin s alır nique şeritler, testkendisi ile temas ettiği, her şerit s (1 dokunmadan değilse, aksi halde 0) ve toplar +/boolean sonucu.

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)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.