Onbeş Bulmacanın Permütasyonları


13

Meydan okuma

Çözülmüş durumda Onbeş Bulmacanın aşağıdaki şemasını düşünün:

_____________________
|    |    |    |    |
| 1  | 2  | 3  | 4  |
|____|____|____|____|
|    |    |    |    |
| 5  | 6  | 7  | 8  |
|____|____|____|____|
|    |    |    |    |
| 9  | 10 | 11 | 12 |
|____|____|____|____|
|    |    |    |    |
| 13 | 14 | 15 |    |
|____|____|____|____|

Her harekette, heyecanlı bir bilinmez boş alana bitişik bir parçayı boş alana taşıma olanağına sahiptir. Örneğin, 1taşındıktan sonra 2olası senaryolarımız var ( 0boş alan olsun):

1   2   3   4          1   2   3   4
5   6   7   8          5   6   7   8
9   10  11  12   and   9   10  11  0
13  14  0   15         13  14  15  12

2Hareketlerden sonra , bulmacanın 5farklı sonuçları vardır (2 hamlede ulaşılamadığından yukarıdaki iki vakanın hariç tutulduğunu unutmayın). Bu durumlardan biri orijinal çözülmüş durumdur ve iki farklı yolla erişilebilir.

Bu meydan okumadaki göreviniz, belirli sayıda hamlenin yol açabileceği farklı sonuçların sayısını üretmektir . Girdi olarak, bir sayı alın N >= 0ve hamlelerden sonra ortaya çıkabilecek benzersiz durumların sayısını Nçıktılayın.

kurallar

  • Bu kod golfü. En kısa kod kazanır!
  • Standart boşluklara izin verilmez.
  • Kodunuz N = 10birkaç dakika içinde vakayı hesaplayabilmelidir . Bir cevapta açıkça zaman kötüye kullanımı olmadığı sürece bu kuralı test etmeyeceğim.

Test Durumları

(Ait toplamları oluşturulan Sonuçları OEIS A089484 (As Geobits açıklanan sohbet Martin BÜTTNER en tarafından otomatik) komut dosyası . Teşekkür tüm yardım için!)

0 moves: 1
1 moves: 2
2 moves: 5
3 moves: 12
4 moves: 29
5 moves: 66
6 moves: 136
7 moves: 278
8 moves: 582
9 moves: 1224
10 moves: 2530
11 moves: 5162
12 moves: 10338
13 moves: 20706
14 moves: 41159
15 moves: 81548
16 moves: 160159
17 moves: 313392
18 moves: 607501
19 moves: 1173136
20 moves: 2244884
21 moves: 4271406
22 moves: 8047295
23 moves: 15055186
24 moves: 27873613
25 moves: 51197332
26 moves: 93009236
27 moves: 167435388
28 moves: 297909255
29 moves: 524507316
30 moves: 911835416
31 moves: 1566529356

Yanıtlar:


5

Pyth, 36 bayt

lu{smmXd,0@dk)fq1.a.DR4,Txd0UdGQ]U16

Gösteri . Kablo demetini test edin.

lu{smmXd,0@dk)fq1.a.DR4,Txd0UdGQ]U16

                 .a.DR4,Txd0            Find the Euclidean distance between the
                                        present location of 0 and a given location.
              fq1           Ud          Filter over all locations on that distance
                                        equaling 1.
     mXd,0@dk)                          Map each such location to the grid with 0
                                        and the value at that location swapped.
  {sm                         G         Map all unique grids possible after n-1
                                        steps to all unique grids after n steps.
 u                             Q]U16    Repeat <input> times, starting with the
                                        initial grid.
l                                       Print the length of the resulting set.

3

CJam, 54 52 51 50 49 47 45 bayt

G,ari{{:S0#S{4md2$4md@-@@-mh1=},f{Se\}}%:|}*,

CJam yorumlayıcısında çevrimiçi deneyin (10 saniyeden az sürmelidir).

Nasıl çalışır

G,a       e# Push R := [[0 1 ... 15]].
ri{       e# Do int(input()) times:
  {:S     e#   For each S in R:
    0#    e#     Push the index of 0 in S (I).
    S{    e#     Filter S; for each J in in S:
      4md e#       Push J/4 and J%4.
      2$  e#       Copy I.
      4md e#       Push I/4 and I%4.
      @-  e#       Compute (I%4)-(J%4).
      @@- e#       Compute (J%4)-(I%4).
      mh  e#       2-norm distance: a b -> sqrt(aa + bb)
      1=  e#       Check if the distance is 1.
    },    e#     Keep all values of J with distance 1 from I.
    f{    e#     For each J:
      S   e#       Push S. 
      e\  e#       Swap S at indexes I and J.
    }     e#     This pushes an array of all valid modifications of S.
  }%      e#   Collect the results for all S in R in an array.
  :|      e#   Reduce the outmost array using set union (removes duplicates).
}*        e#

3

Retina , 289276 bayt

^
,abcd%efgh%ijkl%mnox,
(`(,[^,]*)x([^,%])([^,y]*),
$0$1$2x$3y,
(,[^,]*)([^,%])x([^,y]*),
$0$1x$2$3y,
(,[^,]*)x([^,]{4})([^,])([^,y]*),
$0$1$3$2x$4y,
(,[^,]*)([^,])([^,]{4})x([^,y]*),
$0$1x$3$2$4y,
,.{19},(?=.*1)|,[^,]{20},(?=[^1]*$)|y|1$

+)`([^,]{19})(.*),\1,
$1$2
[^a]

a
1

Girdiyi alır ve çıktıları tekli olarak yazdırır.

Her satırı tek bir dosyaya koyabilir veya kodu -sbayrakta olduğu gibi çalıştırabilirsiniz . Örneğin:

> echo -n 111|retina -s fifteen_puzzle
111111111111

Yöntemin özü, tam olarak kadımlardan sonra oluşabilecek tüm olası konumları (tekrarlama olmadan) takip etmektir . Formu başlatır k = 0ve (` and )` modifiersgirdi adımlarına ulaşana kadar ikame adımlarını () kullanarak tekrarlarız .

Bu hesaplama sırasında dizemiz her zaman

(,[puzzle_state]y?,)+1*

nerede puzzle_stateolduğu abcd%efgh%ijkl%mnoxbazı harflerin permütasyon ile. xboş yer anlamına gelir, kalan harfler fayans. %satır sıralayıcılarıdır.

ydurumun geçerli adımda ( k) oluşturulduğunu belirtir, bu nedenle bu adımda başka durumlar oluşturmak için kullanılmamalıdır.

1'nin kalan adım sayısını işaretleyin.

Retina kodunun temel mekaniği, tek bir çizginin her eşleşmesinin bir sonraki (çift) çizgiye değiştirilmesidir.

Ek açıklama içeren kod:

initialize string
^
,abcd%efgh%ijkl%mnox,

while string changes
(`

for every old (y-less) state concatenate a new state with moving the empty tile to r/l/d/u if possible
right
(,[^,]*)x([^,%])([^,y]*),
$0$1$2x$3y,
left
(,[^,]*)([^,%])x([^,y]*),
$0$1x$2$3y,
down
(,[^,]*)x([^,]{4})([^,])([^,y]*),
$0$1$3$2x$4y,
up
(,[^,]*)([^,])([^,]{4})x([^,y]*),
$0$1x$3$2$4y,

if we should have made this step (there are 1's left) remove old states
,.{19},(?=.*1)

if we should not have made this step (no more 1's left) remove new states
,[^,]{20},(?=[^1]*$)

remove y markers
y

remove one 1 (decrease remaining step count)
1$


remove duplicates until string changes (with + modifier)
+`([^,]{19})(.*),\1,
$1$2    

end while
)`

remove non-a's, 1 a stays from each state
[^a]

change a's to 1's
a
1

@MartinButtner sayesinde 10 bayt tasarruf edildi.


2

Python, 310 253 243 229 bayt

@Randomra tarafından önerilen en son sürüm:

s=set()
s.add(tuple(range(16)))
def e(a,b):s.add(t[:a]+(t[b],)+t[a+1:b]+(t[a],)+t[b+1:])
for k in range(input()):
 p,s=s,set()
 for t in p:j=t.index(0);j%4and e(j-1,j);j%4>2or e(j,j+1);j<4or e(j-4,j);j>11or e(j,j+4)
print len(s)

Daha uzun (243 bayt), ancak okunması daha kolay olan kendi sürümüm:

s=set()
s.add(tuple(range(16)))
def e(a,b):s.add(t[:a]+(t[b],)+t[a+1:b]+(t[a],)+t[b+1:])
for k in range(input()):
 p,s=s,set()
 for t in p:
  j=t.index(0)
  if j%4:e(j-1,j)
  if j%4<3:e(j,j+1)
  if j>3:e(j-4,j)
  if j<12:e(j,j+4)
print len(s)

Basit genişlik ilk arama, devletleri tuples olarak kodlama ve onları benzersiz tutmak için bir kümede saklama.

N = 10 için dizüstü bilgisayarımda yaklaşık 0,03 saniye sürüyor. Daha büyük sayılar için çalışma süresi önemli ölçüde artar, örneğin N = 20 için yaklaşık 12 saniye.


Örtüşme s.addmuhtemelen bazı karakterleri kaydeder .
isaacg

@isaacg Benzer kodu bir fonksiyona taşıyarak biraz tasarruf ettim. Şimdi buna baktığımda, muhtemelen tbir argüman olarak geçmek zorunda değilim . Bunun dışında, eğer daha iyi Python becerilerim varsa, büyük olasılıkla iyileştirme için daha fazla alan olduğunu düşünüyorum.
Reto Koradi

3
Sen dönüştürebilirsiniz ifgibi yan etkisi ile kısa devre ifadelerine ifadeleri j%4and e(j-1,j)bir boolean başlığın olarak bir satır içine koydu böylece: j%4and e(j-1,j),j%4>2or e(j,j+1),j<4or e(j-4,j),j>11or e(j,j+4).
randomra

@randomra Kulağa hoş geliyor, yarın deneyeceğim. Muhtemelen ifade dizileri yerine koşullu ifadeleri kullanmanın akıllıca bir yolu olduğunu düşündüm if. Ayrıca, iki elemanın değiştirildiği bir demet oluşturmanın daha kısa bir yolu olup olmadığını merak ediyorum.
Reto Koradi

1
Listeye dönüştürme takas ve tuplea geri dönüştürme biraz daha kısadır: def e(a,b):*l,=t;l[a],l[b]=l[b],l[a];s.add(tuple(l)).
randomra

1

Perl, 148

#!perl -p
$s{"abcd.efgh.ijkl.mno#"}=1;for(1..$_){$x=$_,map{$r{$_}=1if
s/($x)/$3$2$1/}keys%s for
qw!\w)(# #)(\w \w)(.{4})(# #)(.{4})(\w!;%s=%r;%r=()}$_=keys%s

Misal:

$ time perl 15.pl <<<20
2244884
real    0m39.660s
user    0m38.822s
sys 0m0.336s
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.