我们发现只有25个格子,应该是可以用爆搜过掉这道题的。但是裸的dfs时间复杂度过高,我们要进行相应的优化。
首先,由于马的数量过多,我们应该选择让空格“走”。
接下来我们发现这道题又很明显的一个限制条件,最多不能超过15步,所以我们可以使用迭代加深进行优化,所谓的迭代加深搜索,本质上还是dfs,但是它每次会设置一个深度上限maxdep,使得搜索树的深度不超过maxdep,这样做可以让它遍历更多的分支,更广泛的求解。
然而,即使加上了迭代加深优化,我们依然不能通过此题,因此我们引入了第二种优化:启发式搜索,著名的A*算法就是一种启发式搜索。
来自https://blog.csdn.net/denghecsdn/article/details/78778769的A*核心思想详解:
“A*成功的秘决在于,它把Dijkstra算法(靠近初始点的结点)和BFS算法(靠近目标点的结点)的信息块结合起来。在讨论A*的标准术语中,g(n)表示从初始结点到任意结点n的代价,h(n)表示从结点n到目标点的启发式评估代价(heuristic estimated cost)。在上图中,yellow(h)表示远离目标的结点而teal(g)表示远离初始点的结点。当从初始点向目标点移动时,A*权衡这两者。每次进行主循环时,它检查f(n)最小的结点n,其中f(n) = g(n) + h(n)。”
然而上述思想显然是针对BFS的,我们可以结合迭代加深将其“改造”成我们需要的dfs算法,这种算法就叫做启发式迭代加深搜索(IDA*)
那么回到这个题目本身,我们如何设计这个估价函数呢?我们发现,在最乐观的情况下,每次交换时,都把相应棋子交换到标准位置,因此我们只要统计最终状态和当前状态不一样的数量即可。
然后使用IDA*搜索即可。
参考代码:
1 #pragma GCC optimize(3,"Ofast","inline") 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #define int long long 6 using namespace std; 7 int read() 8 { 9 int x=0,f=1;char ch=getchar(); 10 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 11 while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} 12 return x*f; 13 } 14 int n; 15 int _std[10][10]= 16 { 17 {0,0,0,0,0,0}, 18 {0,1,1,1,1,1}, 19 {0,0,1,1,1,1}, 20 {0,0,0,2,1,1}, 21 {0,0,0,0,0,1}, 22 {0,0,0,0,0,0} 23 }; 24 int dx[8]={-1,1,2,2,1,-1,-2,-2}; 25 int dy[8]={-2,-2,-1,1,2,2,1,-1}; 26 int a[10][10],T,suc,sx,sy; 27 char ch; 28 int evaluate() 29 { 30 int cnt=0; 31 for(int i=1;i<=5;i++) 32 { 33 for(int j=1;j<=5;j++) 34 { 35 if(a[i][j]!=_std[i][j])++cnt; 36 } 37 } 38 return cnt; 39 } 40 void A_star(int step,int x,int y,int maxdep) 41 { 42 if(step==maxdep) 43 { 44 if(!evaluate())suc=step; 45 return; 46 } 47 for(int i=0;i<=7;i++) 48 { 49 int xx=x+dx[i],yy=y+dy[i]; 50 if(xx<1||xx>5||yy<1||yy>5)continue; 51 swap(a[xx][yy],a[x][y]); 52 if(step+evaluate()<=maxdep)A_star(step+1,xx,yy,maxdep); 53 swap(a[xx][yy],a[x][y]); 54 } 55 } 56 signed main() 57 { 58 freopen("knight.in","r",stdin); 59 freopen("knight.out","w",stdout); 60 ios::sync_with_stdio(0); 61 cin>>T; 62 while(T--) 63 { 64 suc=0; 65 for(int i=1;i<=5;i++) 66 { 67 for(int j=1;j<=5;j++) 68 { 69 cin>>ch; 70 if(ch=='*')a[i][j]=2,sx=i,sy=j; 71 else a[i][j]=ch-'0'; 72 } 73 } 74 if(!evaluate()) 75 { 76 cout<<0<<" "; 77 continue; 78 } 79 for(int i=1;i<=15;i++) 80 { 81 A_star(0,sx,sy,i); 82 if(suc)break; 83 } 84 if(suc)cout<<suc<<endl; 85 else cout<<-1<<endl; 86 } 87 return 0; 88 }