【传送门:BZOJ1085】
简要题意:
有一个5*5的棋盘,棋盘上有12个白棋子,12个黑棋子,和一个空格,每只棋子只能按照马走日的规则移动,求出最少步数达到以下状态
题解:
DFS+A*
DFS很容易做,不过时间复杂度太高
所以用A*来优化时间
A*的好处预判当前递归到结束得到的值,从而判断是否进入递归,部分判断,避免遍历太多无用点
参考代码:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; int a[6][6]; const int dx[9]={0,1,1,-1,-1,2,2,-2,-2}; const int dy[9]={0,2,-2,2,-2,1,-1,1,-1}; bool bk; int ans[6][6]= { {0,0,0,0,0,0}, {0,1,1,1,1,1}, {0,0,1,1,1,1}, {0,0,0,2,1,1}, {0,0,0,0,0,1}, {0,0,0,0,0,0} }; bool pd() { for(int i=1;i<=5;i++) for(int j=1;j<=5;j++) if(a[i][j]!=ans[i][j]) return false; return true; } int w; bool pdA(int k) { int s=0; for(int i=1;i<=5;i++) { for(int j=1;j<=5;j++) { if(a[i][j]!=ans[i][j]) { s++; if(s+k>w) return false; } } } return true; } void dfs(int x,int y,int k) { if(bk==true) return ; if(k==w) { if(pd()==true) bk=true; return ; } else { for(int i=1;i<=8;i++) { int tx=x+dx[i],ty=y+dy[i]; if(tx<1||tx>5||ty<1||ty>5) continue; swap(a[x][y],a[tx][ty]); if(pdA(k)==true) dfs(tx,ty,k+1); swap(a[x][y],a[tx][ty]); } } } int main() { int T;scanf("%d",&T); while(T--) { char st[10]; int kx,ky; for(int i=1;i<=5;i++) { scanf("%s",st+1); for(int j=1;j<=5;j++) { if(st[j]==‘*‘) { a[i][j]=2; kx=i,ky=j; } else a[i][j]=st[j]-‘0‘; } } bk=false; for(w=1;w<=15;w++) { dfs(kx,ky,0); if(bk==true) { printf("%d\n",w); break; } } if(bk==false) printf("-1\n"); } return 0; }