15 퍼즐의 순열


13

도전

해결 된 상태의 다음 15 개 퍼즐 다이어그램을 고려하십시오.

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

움직일 때마다 흥분된 퍼즐 게임은 빈 공간에 인접한 한 조각을 빈 공간으로 옮길 수 있습니다. 예를 들어, 1이동 후 2가능한 시나리오가 있습니다 ( 0공백으로 두십시오).

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

2이동 후 퍼즐의 5결과 는 다릅니다 (위의 두 경우는 2 이동에서는 도달 할 수 없으므로 제외됨). 이러한 상황 중 하나는 원래 해결 된 상태이며 두 가지 다른 방식으로 도달 할 수 있습니다.

이 문제에서 당신의 임무는 생산하는 번호 이동의 특정 번호로 이어질 수있는 다른 성과를. 입력으로 숫자를 가져 와서 이동 후 나타날 N >= 0수있는 고유 한 상황 수를 출력하십시오 N.

규칙

  • 이것은 코드 골프입니다. 최단 코드 승리!
  • 표준 허점 은 허용되지 않습니다.
  • 코드는 N = 10몇 분 안에 사례를 계산할 수 있어야합니다 . 대답에 명백한 시간 남용이 없으면이 규칙을 테스트하지 않을 것입니다.

테스트 사례

( Martin Büttner의 스크립트에 의해 자동화 된 OEIS A089484 ( 채팅에 설명 된 Geobits)의 요약에서 생성 된 결과 입니다. 모든 도움에 감사드립니다!)

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

답변:


5

Pyth, 36 바이트

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

데모 . 테스트 하네스.

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 바이트

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

CJam 통역사 에서 온라인으로 사용해보십시오 (10 초 미만 소요).

작동 원리

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

망막 , 289276 바이트

^
,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

단항으로 입력을 받아서 출력을 인쇄합니다.

-s플래그를 사용하여 각 줄을 단일 파일에 넣거나 코드를 실행할 수 있습니다 . 예 :

> echo -n 111|retina -s fifteen_puzzle
111111111111

이 방법의 핵심은 정확한 k단계 후에 발생할 수있는 모든 가능한 위치 (반복없이)를 추적하는 것 입니다. 입력 단계 수에 도달 할 때까지 양식을 시작 k = 0하고 대체 단계 (를 사용하여 (` and )` modifiers) 를 반복 합니다.

이 계산 동안 우리의 문자열은 항상

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

곳이 puzzle_state있습니다 abcd%efgh%ijkl%mnox문자의 일부 순열과 함께. x빈 자리를 의미하고 나머지 글자는 타일입니다. %행 구분 기호입니다.

y상태가 현재 단계 ( k)에서 생성되므로이 단계에서 다른 상태를 생성하는 데 사용해서는 안됩니다.

1남은 걸음 수를 표시합니다.

Retina 코드의 기본 메커니즘은 홀수 라인의 모든 일치 항목이 다음 (짝수) 라인으로 변경된다는 것입니다.

설명이 추가 된 코드 :

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 덕분에 10 바이트가 절약되었습니다.


2

파이썬, 310 253 243 229 바이트

@randomra가 제안한 개선 된 최신 버전 :

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)

더 길지만 (243 바이트) 읽기 쉬운 내 버전 :

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)

간단한 너비 우선 검색, 상태를 튜플로 인코딩하고 고유 한 상태로 유지하기 위해 세트에 저장합니다.

N = 10 동안 랩톱에서 약 0.03 초가 걸립니다. N = 20의 경우 약 12 ​​초와 같이 더 큰 숫자의 경우 실행 시간이 크게 증가합니다.


앨리어싱 s.add은 아마도 일부 문자를 저장했을 것입니다.
isaacg

@isaacg 비슷한 코드를 함수로 이동하여 상당히 절약했습니다. 지금 이것을 보면, 아마도 t논쟁의 여지 가 없어도 됩니다. 그 외에는 더 나은 파이썬 기술이 있다면 개선의 여지가 더 많을 것으로 생각합니다.
Reto Koradi

3
if명령문을 부작용이있는 단락 표현식으로 변환하여 j%4and e(j-1,j)부울 튜플로 한 줄에 넣을 수 있습니다 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 소리 좋은데, 나는 내일 그것을 시도 할 것이다. 나는 일련의 if진술 대신 조건식을 사용하는 영리한 방법이 있다고 생각했습니다 . 또한 두 요소를 교환하여 튜플을 만드는 짧은 방법이 있는지 궁금합니다.
Reto Koradi

1
목록으로 변환, 교환 및 튜플로 다시 변환하는 것이 약간 짧습니다 def e(a,b):*l,=t;l[a],l[b]=l[b],l[a];s.add(tuple(l)).
randomra

1

펄, 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

예:

$ time perl 15.pl <<<20
2244884
real    0m39.660s
user    0m38.822s
sys 0m0.336s
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.