#include<stdio.h> #include<math.h> typedef struct { long parent; long index; int direction;//记录上一节点到当前节点空格移动方向 int Grid[9];//存储局面 int H;//启发函数值 }State; State S,T;//起始态,目标态(目标态由评估函数决定好了) State OPEN[2048];//队列-----待考察的状态 State CLOSE[2048];//--------考察过的状态 int OPhead=0,OPtail=0,openlen=2048; int CLhead=0,CLtail=0,closelen=2048; long INDEX=0;//记录下标 void readdata(); int search(); int Evaluate(State s); State Swap(State v,int Epindex,int Nindex);//交换两个位置上的值 int Judge(State father,int n,int BlankIndex,int NumIndex); void AI_Inspire(); void addtoopen(State v);//将节点v加到队列尾 State takeoutofopen();//取队列头数据 void addtoclose(State v); int main() { readdata();//读取起始状态 int flag=search(); int kk; if(flag==1)//找到了,输出CLOSE表中的考察过的状态 { for(kk=CLhead;kk<CLtail;kk++)//输出从起点到终点的局面变化过程 { printf("第%d个状态: ",kk); for(int jj=0;jj<9;jj++) printf(" %d",CLOSE[kk].Grid[jj]); printf(" 节点扩展下标: %d\n",CLOSE[kk].index); } printf("\n"); /*int i,j,k; State Process[2000]; State End=CLOSE[CLtail-1];//将终点棋局保存起来 for(int ii=CLhead;ii<CLtail-1;ii++)//将考察过的节点按其下标进行排序---升序 { int kk=ii; for(int jj=ii+1;jj<CLtail-1;jj++) if(CLOSE[jj].index <CLOSE[kk].index) kk=jj; State temp=CLOSE[ii]; CLOSE[ii]=CLOSE[kk]; CLOSE[kk]=temp; } int k=0; Process[k++]=End;//取从终点到起点的节点 for(int i=CLtail-2;i>=CLhead;i--) { if(End.parent ==CLOSE[i].index) { Process[k++]=CLOSE[i]; End=CLOSE[i]; } } for(j=k-1;j>=0;j--)//输出从起点到终点的局面变化过程 { printf("第%d个状态: ",k-1-j); for(int jj=0;jj<9;jj++) printf(" %d",Process[j].Grid[jj]); printf("\n"); }*/ } else printf("未找到\n"); return 0; } int search() { State father; while(OPhead != OPtail)//OPEN[]表中还有待考察的数据 { int BlankIndex,NumIndex; father = takeoutofopen();//从队列头取数据 addtoclose(father);//将father节点加入CLOSE表(已考察) for(int k=0;k<9;k++) if(father.Grid[k]==0) { BlankIndex=k; break; } //记录父节点father空格位所在的位置 //////四个方向搜索////// //空格向左移 if(father.direction !=3) { NumIndex=BlankIndex/3*3+BlankIndex%3-1; if(BlankIndex%3-1>=0) { int flag=Judge(father,1,BlankIndex,NumIndex); if(flag==1) return 1; } } //空格向上移 if(father.direction !=4) { NumIndex=(BlankIndex/3-1)*3+BlankIndex%3;//计算待移动的数据所在的位置 if(BlankIndex/3-1>=0) { int flag=Judge(father,2,BlankIndex,NumIndex); if(flag==1) return 1; } } //空格向右移 if(father.direction !=1) { NumIndex=BlankIndex/3*3+BlankIndex%3+1; if(BlankIndex%3+1<3) { int flag=Judge(father,3,BlankIndex,NumIndex); if(flag==1) return 1; } } //空格向下移 if(father.direction !=2) { NumIndex=(BlankIndex/3+1)*3+BlankIndex%3; if(BlankIndex/3+1<3) { int flag=Judge(father,4,BlankIndex,NumIndex); if(flag==1) return 1; } } AI_Inspire();//调整OPEN标 } return 0; } void AI_Inspire() { //按启发函数值对OPEN表中的元素进行排序----降序 State temp[2048]; int t=0; int ii,jj; //取出 if(OPtail<OPhead) { for(ii=OPhead;ii<2048;ii++) temp[t++]=OPEN[ii]; for(ii=0;ii<OPtail;ii++) temp[t++]=OPEN[ii]; } else { for(ii=OPhead;ii<OPtail;ii++) temp[t++]=OPEN[ii]; } //排序 for(ii=0;ii<t;ii++) { int kk=ii; for(jj=ii+1;jj<t;jj++) if(temp[jj].H >= temp[kk].H) //正确位码的个数大的放在队列的最前面,优先展开 kk=jj; State tp=temp[ii]; temp[ii]=temp[kk]; temp[kk]=tp; } //printf("%d---",temp[0].H);//调试 //放回 t=0; if(OPtail<OPhead) { for(ii=OPhead;ii<2048;ii++) OPEN[ii]=temp[t++]; for(ii=0;ii<OPtail;ii++) OPEN[ii]=temp[t++]; } else { for(ii=OPhead;ii<OPtail;ii++) OPEN[ii]=temp[t++]; } //printf("%d\n",OPEN[OPhead].H);//调试 } int Judge(State father,int n,int BlankIndex,int NumIndex) { State son; son.parent =father.index ;//1.子节点明确自己的父节点下标 son.direction = n; for(int i=0;i<9;i++) son.Grid[i]=father.Grid[i];//3.子节点局面复制父节点局面 son=Swap(son,BlankIndex,NumIndex);//3.son(f)->son son.H=Evaluate(son);//4.子节点的启发函数值 if(son.H==T.H) { son.index =INDEX++; addtoclose(son); return 1; //表明找到了终点 } else { son.index =INDEX++; //2.子节点自己的下标---father.index*4+n以指数形式增长,会超出long的范围(不能用) addtoopen(son);//将当前状态节点加入到OPEN表 } return 0; } void addtoopen(State v) { OPEN[OPtail++]=v; //向尾部添加节点 OPtail = OPtail%openlen; } State takeoutofopen()//从队列头取节点数据 { State v; v=OPEN[OPhead++];//向头部取节点 OPhead=OPhead%openlen; return v; } void addtoclose(State v) { CLOSE[CLtail++]=v; CLtail = CLtail%closelen; } //v为传入的局面,BlankIndex为空格位置,NumIndex为被交换的数据位置 State Swap(State son,int BlankIndex,int NumIndex) { int temp=son.Grid[BlankIndex];//取空格位置的数字 son.Grid[BlankIndex]=son.Grid[NumIndex]; son.Grid[NumIndex]=temp; return son;//返回新局面 } int Evaluate(State s)//启发式函数 { int count=0;//正确位码的个数 for(int i=0;i<9;i++) { if(s.Grid[i]==T.Grid[i] && s.Grid[i]!=0) count++; } return count;//返回逆序值 } void readdata() { int Arr[10]={8,7,6,5,4,3,2,1,0}; int Brr[10]={0,1,2,3,4,5,6,7,8}; //28步 //终止局面 T.index=-1;//1 T.parent=-1;//2 for(int i=0;i<9;i++)//4 T.Grid[i]=Arr[i]; T.H=Evaluate(T);//5 //起始局面 S.index=INDEX++; S.parent=-1; for(i=0;i<9;i++) S.Grid[i]=Brr[i]; S.H=Evaluate(S);//起始局面评估 addtoopen(S); }
测例:
第0个状态: 0 1 2 3 4 5 6 7 8 节点扩展下标: 0
第1个状态: 3 1 2 0 4 5 6 7 8 节点扩展下标: 2
第2个状态: 3 1 2 6 4 5 0 7 8 节点扩展下标: 4
第3个状态: 3 1 2 6 4 5 7 0 8 节点扩展下标: 5
第4个状态: 3 1 2 6 4 5 7 8 0 节点扩展下标: 7
第5个状态: 3 1 2 6 4 0 7 8 5 节点扩展下标: 8
第6个状态: 3 1 0 6 4 2 7 8 5 节点扩展下标: 10
第7个状态: 3 0 1 6 4 2 7 8 5 节点扩展下标: 11
第8个状态: 0 3 1 6 4 2 7 8 5 节点扩展下标: 12
第9个状态: 6 3 1 0 4 2 7 8 5 节点扩展下标: 14
第10个状态: 6 3 1 7 4 2 0 8 5 节点扩展下标: 16
第11个状态: 6 3 1 7 4 2 8 0 5 节点扩展下标: 17
第12个状态: 6 3 1 7 4 2 8 5 0 节点扩展下标: 19
第13个状态: 6 3 1 7 4 0 8 5 2 节点扩展下标: 20
第14个状态: 6 3 0 7 4 1 8 5 2 节点扩展下标: 22
第15个状态: 6 0 3 7 4 1 8 5 2 节点扩展下标: 23
第16个状态: 0 6 3 7 4 1 8 5 2 节点扩展下标: 24
第17个状态: 7 6 3 0 4 1 8 5 2 节点扩展下标: 26
第18个状态: 7 6 3 8 4 1 0 5 2 节点扩展下标: 28
第19个状态: 7 6 3 8 4 1 5 0 2 节点扩展下标: 29
第20个状态: 7 6 3 8 4 1 5 2 0 节点扩展下标: 31
第21个状态: 7 6 3 8 4 0 5 2 1 节点扩展下标: 32
第22个状态: 7 6 0 8 4 3 5 2 1 节点扩展下标: 34
第23个状态: 7 0 6 8 4 3 5 2 1 节点扩展下标: 35
第24个状态: 0 7 6 8 4 3 5 2 1 节点扩展下标: 36
第25个状态: 8 7 6 0 4 3 5 2 1 节点扩展下标: 38
第26个状态: 8 7 6 5 4 3 0 2 1 节点扩展下标: 40
第27个状态: 8 7 6 5 4 3 2 0 1 节点扩展下标: 41
第28个状态: 8 7 6 5 4 3 2 1 0 节点扩展下标: 43