bzoj1085 [SCOI2005]骑士精神 ( 迭代加深搜索 + A*启发式搜索 )

bzoj1085 [SCOI2005]骑士精神

原题地址http://www.lydsy.com/JudgeOnline/problem.php?id=1085

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

如果能在15步内完成,输出步数,否则输出-1。

数据范围
数据组数 T<=10

题解:
要求15步内完成,但是广搜状态很多,于是考虑迭代加深搜索。

A*估价函数剪枝,既要要力度合理,且不要把正解减去了,
那么既然有了IDA的当前深度的限制,就把“当前最少要走的都超了”的减去。
最少要走的步数即是和最终图不一样的数量-1。

这个估价函数可以在交换两个格子时顺便维护。

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int T,n=5;
int a[10][10],s[10][10];
int fx[8]={1,1,-1,-1,2,2,-2,-2},fy[8]={2,-2,2,-2,1,-1,1,-1};
char ss[10][10];
bool check()
{
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    if(a[i][j]!=s[i][j]) return 0;
    return 1;
}
bool dfs(int now,int x,int y,int enval,int dep)
{
    if(now==dep) return check();
    for(int i=0;i<8;i++)
    {
        int X=x+fx[i]; int Y=y+fy[i];
        if(X<=0||X>5||Y<=0||Y>5) continue;
        int pre=(a[x][y]!=s[x][y])+(a[X][Y]!=s[X][Y]);
        swap(a[x][y],a[X][Y]);
        int nn=(a[x][y]!=s[x][y])+(a[X][Y]!=s[X][Y]);
        int nenv=enval-pre+nn;
        if(nenv+now<=dep)
         if(dfs(now+1,X,Y,nenv,dep)) return 1;
        swap(a[x][y],a[X][Y]);
    }
    return 0;
}
int main()
{
    scanf("%d",&T);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    {
        if((i<=2&&j>=i)||(j>i)) s[i][j]=1;
        else if(i==j&&i==3)  s[i][j]=-1;
        else s[i][j]=0;         
    }       
    while(T--)
    {
        for(int i=1;i<=n;i++)
        scanf("%s",ss[i]+1);
        int cnt=0; 
        int sx,sy;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            if(ss[i][j]=='1') a[i][j]=1; 
            else if(ss[i][j]=='*') {a[i][j]=-1;sx=i;sy=j;}
            else a[i][j]=0;
            if(a[i][j]!=s[i][j]) cnt++; 
        }
        if(cnt==0) {printf("0\n"); continue;}
        cnt--;
        bool flag=0;
        for(int dep=1;dep<=15;dep++)
        {
            if(dfs(0,sx,sy,cnt,dep))
            {printf("%d\n",dep); flag=1; break;}
        }
        if(!flag) printf("-1\n");       
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值