BZOJ1085 骑士精神【IDA*算法】

Description

  在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空位上。 给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步数完成任务。
Input
  第一行有一个正整数T(T<=10),表示一共有N组数据。接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑
士,*表示空位。两组数据之间没有空行。
Output
  对于每组数据都输出一行。如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1。

题解

首先想到搜索,但是BFS和DFS是肯定不行的,我们注意到答案在15步之外就不需要再搜索了,题目很显然在提醒我们往迭代加深上思考。估价函数可以用当前图与目标图不匹配的个数-1(由于最后一次移动有可能移动一次使两个方格都匹配,所以要-1);
代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define n 5
using namespace std;
const char gT[5][5]={{'1','1','1','1','1'},
                     {'0','1','1','1','1'},
                     {'0','0','*','1','1'},
                     {'0','0','0','0','1'},
                     {'0','0','0','0','0'}};
const int flg[8][2]={{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1}};
int tet,ans,nowx,nowy,h,X,Y;
char map[5][5];
bool check(int x,int y){
    if(x<0||x>4||y<0||y>4)return 0;
    return 1;
}
bool IDA_star(int step){
    if(step+h-1>ans)return 0;
    if(!h)return 1;
    for(int i=0;i<8;i++) if(check(nowx+flg[i][0],nowy+flg[i][1])){
        int th=h;
        if(map[nowx][nowy]==gT[nowx+flg[i][0]][nowy+flg[i][1]])h--;
        if(gT[nowx][nowy]==map[nowx+flg[i][0]][nowy+flg[i][1]])h--;
        if(map[nowx+flg[i][0]][nowy+flg[i][1]]==gT[nowx+flg[i][0]][nowy+flg[i][1]])h++;
        if(map[nowx][nowy]==gT[nowx][nowy])h++;
        swap(map[nowx][nowy],map[nowx+flg[i][0]][nowy+flg[i][1]]);nowx+=flg[i][0];nowy+=flg[i][1];
        if(IDA_star(step+1))return 1;
        swap(map[nowx][nowy],map[nowx-flg[i][0]][nowy-flg[i][1]]);nowx-=flg[i][0];nowy-=flg[i][1];h=th;
    }
    return 0;
}
int main(){
    freopen("knight.in","r",stdin);
    freopen("knight.out","w",stdout);
    scanf("%d",&tet);getchar();
    while(tet--){
        ans=h=0;
        for(int i=0;i<5;i++){
            for(int j=0;j<5;j++){
                map[i][j]=getchar();
                if(map[i][j]!=gT[i][j])h++;
                if(map[i][j]=='*')X=i,Y=j;
            }
            getchar();
        }
        nowx=X;nowy=Y;
        while((!IDA_star(0))&&ans<=15)nowx=X,nowy=Y,ans++;
        printf("%d\n",ans<=15?ans:-1);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值