[SCOI2005]骑士精神

Description

在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑士的走法移动到空位上。 给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步数完成任务。

这里写图片描述


Sample Input

2
10110
01*11
01001
01011
01110
00100

Sample Output

7
-1

可以将空格看成骑士,进行dfs,让它每次与黑或白马交换。
但是时间其实是很多的,我连数据都过不了……
于是我就学习到了A*算法,这个算法主要是评估一个值为当前到目标状态的大概步数,这个评估步数大于实际步数。
若我来到一个状态,可进行判断,是否需要删除,这样可以省略很多无用状态。
但还有一些小优化,因为步数较小,就可以从小到大枚举每一种步数,每次枚举中dfs只判断是否与该步数相等,这样可以省一些时间,也只有这样才可以在我家电脑上过……
这里写图片描述
大视野不用这个优化都可以过。
爆搜的做法会超时,你想要直接把跟A_star有关的删掉。

#include<cstdio>
#include<algorithm>
using namespace std;
const int ed[6][6]={
    {0,0,0,0,0,0},
    {0,1,1,1,1,1},
    {0,0,1,1,1,1},
    {0,0,0,2,1,1},
    {0,0,0,0,0,1},
    {0,0,0,0,0,0}
};
int dx[8]={1,1,-1,-1,2,2,-2,-2};
int dy[8]={2,-2,2,-2,1,-1,1,-1};
int v[6][6],ans;
bool A_star(int s)
{
    int k=0;
    for(int i=1;i<=5;i++)
    {
        for(int j=1;j<=5;j++)
        {
            if(v[i][j]!=ed[i][j])
            {
                k++;
                if(k+s>ans)return 0;
            }
        }
    }
    return 1;
}
bool ok()
{
    for(int i=1;i<=5;i++)
    {
        for(int j=1;j<=5;j++)
        {
            if(v[i][j]!=ed[i][j])return 0;
        }
    }
    return 1;
}
bool bk;
void dfs(int x,int y,int s)
{
    if(s>ans)return;
    if(ok())
    {
        if(s==ans)bk=false;
        return;
    }
    for(int i=0;i<8;i++)
    {
        int nx=x+dx[i],ny=y+dy[i];
        if(nx<=5&&nx>0&&ny<=5&&ny>0)
        {
            swap(v[x][y],v[nx][ny]);
            if(A_star(s))dfs(nx,ny,s+1);
            swap(v[x][y],v[nx][ny]);
        }
    }
}
char ss[10];
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        int sx,sy;
        for(int i=1;i<=5;i++)
        {
            scanf("%s",ss+1);
            for(int j=1;j<=5;j++)
            {
                if(ss[j]=='*')v[i][j]=2,sx=i,sy=j;
                else v[i][j]=ss[j]-'0';
            }
        }
        bk=true;
        for(ans=0;ans<=15;ans++)
        {
            dfs(sx,sy,0);
            if(!bk){printf("%d\n",ans);break;}
        }
        if(bk)printf("-1\n");
    }
    return 0; 
}
  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值