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;
}

 

posted @ 2019-07-09 09:52  nimphy  阅读(95)  评论(0编辑  收藏