所有想练习A*的人都先来敲一下这道题吧。
数据范围即便只有5*5,但朴素的爆搜还是会超时。
因此考虑剪枝。
对于这道题,肯定只要进行最优化剪枝,判断现在走的步数+剩下最少要走的步数,如果大于ans或者15就return;
那么,估价函数怎么写?
利用小学生的思想,将目前的图与目标状态对比一下,还有多少棋子没有归位,那么至少就要走几步(每次最多归位一个)
还有一个技巧:存储空格的位置,这样可以简化搜索。
CODE
#include<cstdio> #include<iostream> using namespace std; const int g[6][6]= { {0,0,0,0,0,0}, {0,2,2,2,2,2}, {0,1,2,2,2,2}, {0,1,1,0,2,2}, {0,1,1,1,1,2}, {0,1,1,1,1,1}, }; const int fx[8]={1,1,-1,-1,2,2,-2,-2},fy[8]={2,-2,2,-2,1,-1,1,-1}; int t,a[6][6],ans,i,j,x,y; char ch; inline int h() { int tot=0; for (int i=1;i<=5;++i) for (int j=1;j<=5;++j) if (a[i][j]!=g[i][j]) ++tot; return tot; } inline void Astar(int k,int x,int y) { if (!h()) ans=k<ans?k:ans; if (k+h()>ans) return; for (int i=0;i<8;++i) { int xx=fx[i]+x,yy=fy[i]+y; if (xx>0&&yy>0&&xx<=5&&yy<=5) { swap(a[x][y],a[xx][yy]); Astar(k+1,xx,yy); swap(a[x][y],a[xx][yy]); } } } int main() { scanf("%d",&t); while (t--) { for (i=1;i<=5;++i) { for (j=1;j<=5;++j) { cin>>ch; if (ch=='0') a[i][j]=1; else if (ch=='1') a[i][j]=2; else x=i,y=j,a[i][j]=0; } } ans=16; Astar(0,x,y); if (ans>15) puts("-1"); else printf("%d ",ans); } return 0; }