First,我们请出在OI界风靡一阵的难题,八数码难题(其实说难也不难):
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int a[10],b[10]={0,1,2,3,8,0,4,7,6,5},chan[1000011][10];
int pd[10][10][10][10][10][10][10][10]={0};
int w[5]={0,-3,3,-1,1};
int zero[1000011],ans[1000011];
int finish(int tail){
for(int i=1;i<=9;i++)
if(b[i]!=chan[tail][i])return 0;//和目标比较每一位,看看是不是目标
return 1;//没有退出代表到了目标
}
void inser(int tail,int head,int wi){
int i;
for(i=1;i<=9;i++)
chan[tail][i]=chan[head][i];//把父亲的状态全部赋给新节点
int open=zero[head]+wi;//找到新建的0的位置
int now=zero[head];//以前0的位置
chan[tail][now]=chan[tail][open];
chan[tail][open]=0;//交换
zero[tail]=open;//记录现在0的位置
ans[tail]=ans[head]+1;//记录步数
}
int hefa(int p,int k){
int open=zero[k]+p;
int pp=zero[k];
if(open<1 || open>9)return 0;//超界
if(p==-1 &&(pp==4 || pp==7))return 0;
if(p==1 &&(pp==3 || pp==6))return 0;//我们要把一维数组想象成二维数组,然后就去想吧
return 1;//可以拓展
}
int ok(int tail){
if(pd[chan[tail][1]][chan[tail][2]][chan[tail][3]][chan[tail][4]][chan[tail][5]][chan[tail][6]][chan[tail][7]][chan[tail][8]])return 0;//如果曾经使用过,就不能再走
pd[chan[tail][1]][chan[tail][2]][chan[tail][3]][chan[tail][4]][chan[tail][5]][chan[tail][6]][chan[tail][7]][chan[tail][8]]=1;return 1;//把它赋为1,返回值为1.
}
void bfs(){
int head=0,tail=1;
do{
head++;
for(int i=1;i<=4;i++){
if(hefa(w[i],head)){//如果可以入队
tail++;
inser(tail,head,w[i]);//加入队列
if(!ok(tail))tail--;//被使用过
if(finish(tail)){//完成了
printf("%d\n",ans[tail]);
exit(0);//找到了就输出,结束程序
}
}
}
}while(head<tail);
}
int main(){
int i,j,k,n,m,head,tail;
int fi,fj;
for(i=1;i<=9;i++){
char c;
scanf("%c",&c);
a[i]=c-'0';
if(!a[i]){
fi=i;
}
chan[1][i]=a[i];
}//模拟字符串读入,转成数组
tail=1;
zero[tail]=fi;//队列初始化
pd[chan[tail][1]][chan[tail][2]][chan[tail][3]][chan[tail][4]][chan[tail][5]][chan[tail][6]][chan[tail][7]][chan[tail][8]]=1;//用一个八维数组来判断重复,实现O(1)的复杂度判重
bfs();//广搜,但建立在问题一定有结果的情况下.
return 0;
}
这段代码的核心思想,就是判重:不需要很多的步骤,只需要简单的O(1),但是却让我们失去了太多的空间:10^9!!!要么损时,要么损空。