【SCOI2005】骑士精神
本题在洛谷上的链接:https://www.luogu.org/problemnew/show/P2324
本题在BZOJ上的链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1085
QwQ,IDA*算法太好玩了!
在这里放一波我对迭代加深搜索、A*算法的理解(不一定对):
迭代加深搜索就是枚举DFS的最大深度,然后跑DFS,去验证不超过此深度的前提下是否有解;多用于答案上界很小或是搜索范围没有上界,其实就是防止了DFS一搜到底。
A*算法看起来像是一个剪枝,定义估价函数,乐观地估计从当前状态出发的最终解,若比当前已找到的解还要差,不用多说,剪掉!
迭代加深搜索又叫IDS,用在一起就叫IDA*了。。。
说说这道题,从看完课件里的分析到A掉没用多少时间,可能IDA*的做法比较固定。不过最可能的原因,就像课件里讲的,这类题最关键的就是找到估价函数。
估价函数找的时候往往需要转化一下,每次移动都会改变一个非空格子的状态,那么最少移动步数一定大于等于不相同格子的数目。一开始我只是单纯地扫了一下统计不同的个数,但忽略了一点,一次移动会使两个格子发生变化:初始的空格子和移动后的空格子。这样,并不是已移动的步数加上不相同格子的数目大于当前解就剪枝,而是将两数之和减1再比较。
1 #include<cstdio> 2 const int aim[6][6]={ 3 {0,0,0,0,0,0}, 4 {0,1,1,1,1,1}, 5 {0,0,1,1,1,1}, 6 {0,0,0,-1,1,1}, 7 {0,0,0,0,0,1}, 8 {0,0,0,0,0,0} 9 }; 10 const int mov[8][2]={{-2,-1},{-2,1},{2,-1},{2,1},{-1,-2},{1,-2},{-1,2},{1,2}}; 11 int T,mt[6][6],ans,maxd; 12 void dfs(int d,int x,int y) { 13 if(d>maxd) return; 14 int flag=1,diff=0; 15 for(int i=1;i<=5;++i) { 16 for(int j=1;j<=5;++j) 17 if(mt[i][j]!=aim[i][j]) {flag=0;++diff;} 18 } 19 if(flag) { 20 if(d<ans) ans=d; 21 return; 22 } 23 if(d+diff-1>maxd) return; 24 for(int i=0;i<8;++i) { 25 int nx=x+mov[i][0],ny=y+mov[i][1]; 26 if(nx<1||nx>5||ny<1||ny>5) continue; 27 mt[x][y]=mt[nx][ny]; 28 mt[nx][ny]=-1; 29 dfs(d+1,nx,ny); 30 mt[nx][ny]=mt[x][y]; 31 mt[x][y]=-1; 32 } 33 } 34 int main() { 35 scanf("%d",&T); 36 while(T--) { 37 int sx,sy; 38 char c; 39 for(int i=1;i<=5;++i) 40 for(int j=1;j<=5;++j) { 41 while((c=getchar())=='\n'||c==' '||c=='\r'); 42 mt[i][j]=c=='*'?-1:c-'0'; 43 if(c=='*') sx=i,sy=j; 44 } 45 int flag=0; 46 ans=25; 47 for(maxd=0;maxd<=15;++maxd) { 48 dfs(0,sx,sy); 49 if(ans<=15) {printf("%d\n",ans);flag=1;break;} 50 } 51 if(!flag) printf("-1\n"); 52 } 53 return 0; 54 }