八数码难题 (codevs 1225)题解
【问题描述】
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
【样例输入】
283104765
【样例输出】
4
【解题思路】
这题要求最少步数,因此为广度优先搜索,用队列实现。最简单的方法就是直接将每种状态存入3×3的数组中,然后将空格往四个方向移动,直至目标状态。
不过,让我们来看一看样例。
按往常来说,如果是存入3×3的数组中,那么样例中应该是 2 8 3
1 0 4
7 6 5
可是,样例却是一串数字,且中间没有空格,那么,这就给了我们一种思路,以字符串的形式存入,然后搜索,与目标状态比较时也方便一些。那么我们就换成字符串来搜索,但是字符串中要注意一下,第三位不能移到第四位,第四位不能移到第三位,因此,我们需要对该数字进行判断,看它属于哪一列,然后再搜索。
不过,这两种方式都会超时(在输出结果的步数比较大的时候),因此,我们需要判重,然而,直接开一个12345678-876543210的布尔型数组会超时,所以,这里我们用到了哈希优化。
【代码实现】
1 type rec=record 2 s:string; 3 s1,dep:longint; 4 end; 5 const di:array[1..4] of longint=(-1,-3,3,1); 6 c:string='123804765'; 7 var a:array[1..100000] of rec; 8 b:string; 9 f,r,i,j,k,x:longint; 10 flag:array[1..1000010] of boolean; 11 procedure bfs; 12 var si:char; 13 i,j,k:longint; 14 begin 15 while f<r do 16 begin 17 inc(f); 18 case a[f].s1 of//判断数字属于哪一列 19 2,5,8: 20 for i:=1 to 4 do 21 if (a[f].s1+di[i]>=1)and(a[f].s1+di[i]<=9) then 22 begin 23 inc(r); 24 a[r]:=a[f]; 25 a[r].s[a[r].s1]:=a[r].s[a[r].s1+di[i]]; 26 a[r].s[a[r].s1+di[i]]:='0'; 27 a[r].s1:=a[r].s1+di[i]; 28 inc(a[r].dep); 29 val(a[r].s,x); 30 if not(flag[x mod 1000009]) then 31 dec(r) 32 else 33 begin 34 flag[x mod 1000009]:=false; 35 if a[r].s=c then 36 begin 37 writeln(a[r].dep); 38 halt; 39 end; 40 end; 41 end; 42 1,4,7: 43 for i:=2 to 4 do 44 if (a[f].s1+di[i]>=1)and(a[f].s1+di[i]<=9) then 45 begin 46 inc(r); 47 a[r]:=a[f]; 48 a[r].s[a[r].s1]:=a[r].s[a[r].s1+di[i]]; 49 a[r].s[a[r].s1+di[i]]:='0'; 50 a[r].s1:=a[r].s1+di[i]; 51 inc(a[r].dep); 52 val(a[r].s,x); 53 if not(flag[x mod 1000009]) then 54 dec(r) 55 else 56 begin 57 flag[x mod 1000009]:=false; 58 if a[r].s=c then 59 begin 60 writeln(a[r].dep); 61 halt; 62 end; 63 end; 64 end; 65 3,6,9: 66 for i:=1 to 3 do 67 if (a[f].s1+di[i]>=1)and(a[f].s1+di[i]<=9) then 68 begin 69 inc(r); 70 a[r]:=a[f]; 71 a[r].s[a[r].s1]:=a[r].s[a[r].s1+di[i]]; 72 a[r].s[a[r].s1+di[i]]:='0'; 73 a[r].s1:=a[r].s1+di[i]; 74 inc(a[r].dep); 75 val(a[r].s,x); 76 if not(flag[x mod 1000009]) then 77 dec(r) 78 else 79 begin 80 flag[x mod 1000009]:=false; 81 if a[r].s=c then 82 begin 83 writeln(a[r].dep); 84 halt; 85 end; 86 end; 87 end; 88 end; 89 end; 90 end; 91 begin 92 fillchar(flag,sizeof(flag),true); 93 readln(a[1].s); 94 for i:=1 to 9 do 95 if a[1].s[i]='0' then 96 begin 97 a[1].s1:=i; 98 break; 99 end; 100 f:=0;r:=1; 101 bfs; 102 end.