Hoán vị của mười lăm câu đố


13

Các thách thức

Hãy xem xét sơ đồ sau của Mười lăm câu đố ở trạng thái đã giải:

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

Mỗi lần di chuyển, một người đánh đố hào hứng có cơ hội di chuyển một mảnh liền kề với khoảng trống vào khoảng trống. Ví dụ: sau khi 1di chuyển, chúng ta có 2các tình huống có thể xảy ra (hãy để 0một khoảng trống):

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

Sau khi 2di chuyển, câu đố có 5kết quả khác nhau (Lưu ý rằng hai trường hợp trên được loại trừ, vì chúng không thể đạt được trong 2 lần di chuyển). Một trong những tình huống này là trạng thái được giải quyết ban đầu và có thể đạt được theo hai cách khác nhau.

Nhiệm vụ của bạn trong thử thách này là tạo ra số lượng kết quả khác nhau mà một số lần di chuyển nhất định có thể dẫn đến. Là đầu vào, lấy một số N >= 0và xuất số lượng các tình huống duy nhất có thể xuất hiện sau khi Ndi chuyển.

Quy tắc

  • Đây là môn đánh gôn. Mã ngắn nhất sẽ thắng!
  • Sơ hở tiêu chuẩn là không được phép.
  • Mã của bạn sẽ có thể tính toán trường hợp N = 10trong vòng vài phút. Tôi có thể sẽ không kiểm tra quy tắc này trừ khi có sự lạm dụng thời gian rõ ràng trong câu trả lời.

Các trường hợp thử nghiệm

(Kết quả được tạo từ các bản tóm tắt của OEIS A089484 (Như Geobits được mô tả trong trò chuyện ), được tự động hóa bởi kịch bản của Martin Büttner . Cảm ơn tất cả sự giúp đỡ!)

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

Câu trả lời:


5

Bình thường, 36 byte

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

Trình diễn . Khai thác thử nghiệm.

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 byte

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

Hãy thử trực tuyến trong trình thông dịch CJam (sẽ mất ít hơn 10 giây).

Làm thế nào nó hoạt động

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

Võng mạc , 289 276 byte

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

Đưa đầu vào và in đầu ra trong unary.

Bạn có thể đặt từng dòng trong một tệp duy nhất hoặc chạy mã như với -scờ. Ví dụ:

> echo -n 111|retina -s fifteen_puzzle
111111111111

Cốt lõi của phương pháp là chúng tôi theo dõi tất cả các vị trí có thể (không lặp lại) có thể xảy ra sau kcác bước chính xác . Chúng tôi bắt đầu biểu mẫu k = 0và lặp lại các bước thay thế (sử dụng (` and )` modifiers) cho đến khi chúng tôi đạt được số bước đầu vào.

Trong quá trình tính toán này, chuỗi của chúng tôi luôn có dạng

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

nơi puzzle_stateabcd%efgh%ijkl%mnoxvới một số hoán vị của các chữ cái. xlà viết tắt của chỗ trống, phần còn lại của các chữ cái là gạch. %là các dấu phân cách hàng.

yđánh dấu rằng trạng thái được tạo trong bước hiện tại ( k) vì vậy nó không nên được sử dụng để tạo các trạng thái khác trong bước này.

1Đánh dấu số bước còn lại.

Cơ chế cơ bản của mã Retina là mọi trận đấu của một dòng lẻ được thay đổi thành dòng tiếp theo (chẵn).

Các mã với giải thích thêm:

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

10 byte được lưu nhờ @MartinButtner.


2

Python, 310 253 243 229 byte

Phiên bản mới nhất với cải tiến được đề xuất bởi @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)

Phiên bản của riêng tôi, dài hơn (243 byte), nhưng dễ đọc hơn:

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)

Tìm kiếm đầu tiên đơn giản, mã hóa các trạng thái dưới dạng bộ dữ liệu và lưu trữ chúng trong một bộ để giữ cho chúng là duy nhất.

Mất khoảng 0,03 giây trên máy tính xách tay của tôi cho N = 10. Thời gian chạy không tăng đáng kể đối với số lượng lớn hơn, ví dụ khoảng 12 giây cho N = 20.


Aliasing s.addcó thể sẽ lưu một số nhân vật.
isaacg

@isaacg Tôi đã tiết kiệm được một chút bằng cách di chuyển mã tương tự vào một hàm. Nhìn vào điều này bây giờ, tôi có lẽ không phải vượt qua tnhư một cuộc tranh cãi. Ngoài ra, tôi cho rằng nhiều khả năng sẽ có nhiều cải tiến hơn nếu tôi có kỹ năng Python tốt hơn.
Reto Koradi

3
Bạn có thể chuyển đổi if câu lệnh thành các biểu thức ngắn mạch với hiệu ứng phụ như thế j%4and e(j-1,j)để bạn có thể đặt chúng thành một dòng dưới dạng một bộ dữ liệu boolean : 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).
ngẫu nhiên

@randomra Nghe hay đấy, tôi sẽ thử vào ngày mai. Tôi nghĩ có lẽ có một số cách thông minh để sử dụng các biểu thức điều kiện thay vì chuỗi các ifcâu lệnh. Tôi cũng tự hỏi nếu có một cách ngắn hơn để xây dựng một tuple với hai yếu tố hoán đổi.
Reto Koradi

1
Chuyển đổi sang danh sách, hoán đổi và chuyển đổi trở lại thành tuple ngắn hơn một chút : def e(a,b):*l,=t;l[a],l[b]=l[b],l[a];s.add(tuple(l)).
ngẫu nhiên

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

Thí dụ:

$ time perl 15.pl <<<20
2244884
real    0m39.660s
user    0m38.822s
sys 0m0.336s
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.