BZOJ 1085 [SCOI2005]骑士精神 A*搜索

题目大意:在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空位上。 给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步数完成任务。(最多15步)
这里写图片描述

实在是太懒了不写简化题意了…
当时做的时候都没考虑到A*估价函数的概念只觉得是个普通的DFS剪枝…

骑士移动到空位上可以看成是空位与 能走到这个位置的骑士交换
估价函数即当前没有在正确位置上的骑士数量,表示至少还要这些步才能到达终态。

#include <cstdio>
using namespace std;
char m[6][6];
int xx[8]={1,1,-1,-1,2,2,-2,-2},yy[8]={2,-2,2,-2,1,-1,1,-1};
int ans;
inline void Swap(char &a,char &b) {char c=a;a=b;b=c;}
inline char pos(int x,int y) {
    if(x==1) return '1';
    if(x==2){
        if(y==1) return '0';
        return '1';
    }
    if(x==3){
        if(y<=2) return '0';
        if(y==3) return '*';
        return '1';
    }
    if(x==4){
        if(y<=4) return '0';
        return '1';
    }
    return '0';
}
inline bool check() {
    for(int i=1;i<=5;i++)
        for(int j=1;j<=5;j++)
            if(m[i][j]!=pos(i,j))
                return false;
    return true;
}
void dfs(int p,int x,int y,int w,int b,int lasxx,int lasyy) {
    if(p>=ans) return ;
    if(ans-p-1 < 12-w+12-b) return ;
    if(w==12 && b==12){
        if(p<ans) ans=p;
        return ;
    }
    char cur=pos(x,y);
    for(int i=0;i<8;i++) {
        int nx=x+xx[i],ny=y+yy[i],nw=w,nb=b;
        if(nx<1 || ny<1 || nx>5 || ny>5) continue;
        if(nx==lasxx && ny==lasyy) continue;
        char to=pos(nx,ny);
        if(m[nx][ny]=='1' && cur=='1' && to!='1') nb++;
        if(m[nx][ny]=='0' && cur=='0' && to!='0') nw++;
        if(m[nx][ny]=='1' && to=='1' && cur!='1') nb--;
        if(m[nx][ny]=='0' && to=='0' && cur!='0') nw--;
        Swap(m[x][y],m[nx][ny]);
        dfs(p+1,nx,ny,nw,nb,x,y);
        Swap(m[x][y],m[nx][ny]);
    }
    return ;
}
int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        for(int i=1;i<=5;i++) scanf("%s",m[i]+1);
        int w,b,stx,sty;
        w=b=0;
        for(int i=1;i<=5;i++)
            for(int j=1;j<=5;j++) {
                if(m[i][j]=='0' && pos(i,j)==m[i][j]) w++;
                else if(m[i][j]=='1' && pos(i,j)==m[i][j]) b++;
                else if(m[i][j]=='*') stx=i , sty=j;
            }
        ans=16;
        if(ans-1 >= 12-w+12-b) dfs(0,stx,sty,w,b,0,0);
        if(ans==16) printf("-1\n");
        else printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值