题目大意:
给你一个“井”子状的board,对称的由24个方块组成,每个方块上有123三个数字中的一个。给你初始状态,共有八种变换方式,求字典序最小的最短的的变换路径使得,board中间的八个方块上数字相同。(建议看下题目中的图就懂啦)。
IDA*搜索。
我是干脆用结构体保存搜索状态(当然这样很占空间了,可能也耗时间,不过这题15s/150M的时空限制我也是醉了)。保存一个board temp,一个搜索路径path,搜索深度n,以及一个内置的估值函数h()。h()返回的是8减这八个方块上出现最多的数字的次数,因为一次变换只能改变一个数字的个数,所以h()是比实际小的,满足A*条件。接下来就是迭代dfs搜索了。设置一个初值为0的max,当h()时,表示搜到目标,打印然后return true;若n+h()<=max(这其实就是A*的剪枝思想了),往下向八个方向搜索(用数组dir保存)。若有一个方向成功,则return true;都没成功返回false。max反复++,直至搜到答案。
个人觉得ida*比a*的题目要好写呢。。果然dfs比bfs要友善很多啊。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<string> using namespace std; int board[24]; int aim[8]={6,7,8,11,12,15,16,17}; //8个方向,比下标大1 int dir[8][7]= {1,3,7,12,16,21,23, 2,4,9,13,18,22,24, 11,10,9,8,7,6,5, 20,19,18,17,16,15,14, 24,22,18,13,9,4,2, 23,21,16,12,7,3,1, 14,15,16,17,18,19,20, 5,6,7,8,9,10,11 }; char diralpha[9]="ABCDEFGH"; struct tnode { int temp[24]; string path; int n; inline int h() { int a=0,b=0,c=0; for(int i=0;i<8;i++) { if(temp[aim[i]]==1) a++; else if(temp[aim[i]]==2) b++; else c++; } return 8-max(a,max(b,c)); } }; bool dfs(int mmax,tnode x) { if(x.h()==0) { if(x.n==0) printf("No moves needed %d ",x.temp[aim[0]]); else cout<<x.path<<endl<<x.temp[aim[0]]<<endl; return true; } if(x.n+x.h()<=mmax) { tnode y; for(int i=0;i<8;i++) { y=x; y.path+=diralpha[i]; y.n++; for(int j=0;j<7;j++) y.temp[dir[i][j]-1]=x.temp[dir[i][(j+1)%7]-1]; if(dfs(mmax,y)) return true; } } return false; } int main() { while(scanf("%d",board),board[0]) { for(int i=1;i<24;i++) scanf("%d",board+i); tnode st; memcpy(st.temp,board,sizeof(board)); st.n=0; st.path=""; for(int i=0,flag=false;flag==false;i++) { flag=dfs(i,st); } } return 0; }
PS:某学长想用3进制数判重写,然后MLE了无数发。。(?)所以之后要不要考虑自己也作死一发呢。
PS2:最近没怎么更新博客。。也是比较颓,没有好好学习,好好做题(愧疚)。今天算是好好学习了一天吧。。但愿能够坚持下去。。Keep going and never give up!