八数码就是指在一个3*3的棋盘中有1-8八个数字和一个空格,空格可以与相邻(如果存在)的四个格子交换,得到形如"12345678(空格)"的状态.因为只有九个数字,九个格子,总状态数不会超过9!=326880种.解法可以用深搜,广搜,启发式搜索等等...之所以写八数码是因为在2008 TopCoder China Tournarment Round 1E的1000分的题就是关于八数码的.当时没做出来,想去google search one code...结果打成八码数了,死活就一两个结果,这RP...比赛完才发现打错字了.后大四一学长说这是人工智能课里的一个例子.人工智能好像是下学期的课...不管了.在POJ上也有一道关于八数码的题,网址如下:POJ 1077 : Eight 在TC里面ACRush的1000分的题得分最高,看了他的代码,受益良多.教主境界果然和我们小菜就是不一样.代码短,速度快.照着ACRush的思路 写了一个往TC上交了,运行Run System Test 就AC了,后来又上POJ看1077,花了很长时间写出了下面的代码,POJ上时间卡得蛮紧的...放这里,留个纪念吧.发现TC也蛮好玩的,虽然现在还很菜...经过2008 TopCoder China Tournarment的三场比赛和Round 2,终于变蓝了,下次就是DIV1了,得做好被"虐"的心理准备..
如下所示初始状态:
123
485
76.
存在一个最优移动步骤如下:
123 123 123 123 123
485 --> 485 --> 4.5 --> 45. --> 456
76. 7.6 786 786 78.
下面是用广搜解法(POJ 1077):数据输入方式为按行优先,空格用x替代.

八数码(广搜)
1 #include <iostream>
2 #include <cstring>
3 #include <string>
4 using namespace std;
5
6 #define M 326881
7
8 //定义交换数组,off[i][0]表示空格在i处时可以与之交换
9 //的位置数,后面的与之交换的位置
10 int off[9][5]={
11 {2,1,3},{3,0,2,4},{2,1,5},
12 {3,0,4,6},{4,1,3,5,7},{3,2,4,8},
13 {2,3,7},{3,4,6,8},{2,5,7}
14 };
15
16 //定义队列,str表示当前状态,l表示空格所在位置,f表示上一状态的编号
17 struct Que{
18 char str[10];
19 int l, f;
20 }que[326881], ss, tt;
21
22 //队列的头和尾
23 int front=0, rear=0;
24
25 //hash数组,作判重用
26 struct Hash{
27 char str[10];
28 Hash* next;
29 }hash2[326881];
30
31 int hash2Num=1;
32
33 struct Node{
34 Hash *next;
35 }hash[326881];
36
37 //字符串的hash函数
38 int hashKey(char *str){
39 unsigned long ret=0;
40 int i=0;
41 while(str[i]){
42 ret=(ret<<4)+ *str++;
43 unsigned long g= ret & 0Xf0000000L;
44 if(g) ret ^= g>>24;
45 ret &= ~g;
46 }
47 return ret%M;
48 }
49
50 //计算是上一步与此步的移动方向
51 //u --> up
52 //d --> down
53 //r --> right
54 //l --> left
55 char getAns(int f1, int f2){
56 int t1=f1/3, t2=f1%3; //得到行列位置
57 int l1=f2/3, l2=f2%3; //得到行列位置
58
59 //判断移动方向
60 if(t1-l1==1)
61 return 'u';
62 if(l1-t1==1)
63 return 'd';
64
65 if(t2-l2==1)
66 return 'l';
67 if(l2-t2==1)
68 return 'r';
69
70 }
71 void outputAnswer(int ls){
72 char ans[326881];
73 int len=326880;
74 while(que[ls].f!=-1){
75 //得到两个状态空格所在位置
76 int f1=que[ls].l, f2=que[que[ls].f].l;
77
78 ans[len--]=getAns(f2, f1);
79 ls=que[ls].f;
80 }
81 //输出从超始态到目标态的移动步骤
82 for(++len; len<326881; ++len)
83 putchar(ans[len]);
84
85 }
86
87 void slove(char* str){
88 memcpy(ss.str, str, 10);
89 //得到起始状态
90 for(int i=0; i<9; ++i)
91 if(str[i]=='x'){
92 ss.str[i]='9';
93 ss.l=i;
94 str[i]='0';
95 break;
96 }
97 //看是否己达到目标状态
98 if(strcmp(ss.str,"123456789")==0)
99 return;
100 int no=0;
101 int t=hashKey(ss.str);
102 memcpy(hash2[0].str, ss.str, 10);
103 hash[t].next=&hash2[0];
104 hash2Num=1;
105
106 ss.f=-1;
107 que[front++]=ss;
108 while(true){
109 //队列空,无解
110 if(rear==front){
111 puts("unsolvable");
112 return;
113 }
114 int l=que[rear].l; //得到'9'(x)所在的位置
115 for(int i=1; i<=off[l][0]; ++i){
116
117 //将空格与相邻位置交换
118 swap(que[rear].str[l], que[rear].str[off[l][i]]);
119 int t=hashKey(que[rear].str);
120 bool exist=true;
121 //查找此状态是否己经存在
122 for(Hash *h=hash[t].next; h!=NULL; h=h->next){
123 if(strcmp(h->str, que[rear].str)==0){
124 exist=false;
125 break;
126 }
127 }
128 //如果状态不存在,则放入队列
129 if(exist){
130 memcpy(que[front].str, que[rear].str, 10);
131 que[front].l=off[l][i];
132 que[front].f=rear;
133 //判断是否己经达到目标态
134 if(strcmp(que[front].str,"123456789")==0){
135 swap(que[rear].str[l], que[rear].str[off[l][i]]);
136 outputAnswer(front);
137 return;
138 }
139 ++front;
140 //加入到判重链表中.
141 memcpy(hash2[hash2Num].str, que[rear].str, 10);
142 hash2[hash2Num].next=hash[t].next;
143 hash[t].next=&hash2[hash2Num];
144 ++hash2Num;
145 }
146 swap(que[rear].str[l], que[rear].str[off[l][i]]);
147
148 }
149 ++rear;
150 }
151
152
153 }
154
155
156 int main(){
157 char s[10];
158 s[9]='\0';
159 //输入起始状态,x表示空格
160 for(int i=0; i<9; ++i)
161 cin>>s[i];
162 memset(hash, NULL, sizeof(hash));
163 slove(s);
164 return 0;
165 }