BZOJ-1085:骑士精神 (迭代加深 + A*搜索)
题意:给定一个5*5的棋盘,上面有白马给妈给12匹,以及一个空格。问是否能在15步内有给定棋盘转移到目标棋盘。
如果可以,输出最小步数。 否则输出-1;
思路:由于步数比较小,我们就直接不记录状态vis[]用BFS求了。 直接搜索(即可能会多次走到同一状态)。
- 减枝1:f()=g()+h(),g是当前步数,h是至少的步数,如果f>K,则没必要继续下推搜索。
- 减枝2:没必要回走。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=7; char a[maxn][maxn]; char b[maxn][maxn]={ "000000", "011111", "001111", "000*11", "000001", "000000" }; int dx[8]={2,1,2,1,-1,-2,-1,-2}; int dy[8]={1,2,-1,-2,2,1,-2,-1}; bool check() { rep(i,1,5) rep(j,1,5) if(a[i][j]!=b[i][j]) return false; return true; } int h() { int res=0; rep(i,1,5) rep(j,1,5) res+=(a[i][j]!=b[i][j]); return res-1; } bool dfs(int step,int K,int from,int x,int y) { if(step>K) return false; if(check()) return true; rep(i,0,7) { if(from+i==7) continue; int nx=x+dx[i]; int ny=y+dy[i]; if(nx<1||nx>5||ny<1||ny>5) continue;//"或"优于"且" swap(a[x][y],a[nx][ny]); if(step+h()<=K){ if(dfs(step+1,K,i,nx,ny)) return true; } swap(a[x][y],a[nx][ny]); } return false; } int main() { int T,Sx,Sy; scanf("%d",&T); while(T--){ rep(i,1,5) scanf("%s",a[i]+1); rep(i,1,5) rep(j,1,5) { if(a[i][j]=='*'){ Sx=i; Sy=j; } } int ans=-1; rep(i,0,15) { if(dfs(0,i,-10,Sx,Sy)){ ans=i; break; } } printf("%d\n",ans); } return 0; }
It is your time to fight!