[SCOI2005]骑士精神

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

题解:

IDA*

搜索。

非常友好。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int T;
char ch[7];
int a[7][7],b[7][7]={{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}};
int h(int a0[7][7])
{
    int ret = 0;
    for(int i=1;i<=5;i++)
        for(int j=1;j<=5;j++)
            ret+=(a0[i][j]!=b[i][j]);
    return ret;
}
bool judge(int a0[7][7])
{
    for(int i=1;i<=5;i++)
        for(int j=1;j<=5;j++)
            if(a0[i][j]!=b[i][j])
                return 0;
    return 1;
}
int ans,lim;
int dx[]={-2,2,-1,1,-1,1,-2,2};
int dy[]={-1,1,-2,2,2,-2,1,-1};
bool check(int x,int y)
{
    return x>=1&&x<=5&&y>=1&&y<=5;
}
void dfs(int a0[7][7],int dep,int x,int y)
{
    if(dep>lim)
    {
        if(judge(a0))ans=lim;
        return ;
    }
    if(~ans)return ;
    for(int i=0;i<8;i++)
    {
        int xx = x+dx[i],yy = y+dy[i];
        if(!check(xx,yy))continue;
        swap(a0[x][y],a0[xx][yy]);
        if(h(a0)+dep-1<=lim)dfs(a0,dep+1,xx,yy);
        swap(a0[x][y],a0[xx][yy]);
    }
}
int main()
{
//    freopen("tt.in","r",stdin);
    scanf("%d",&T);
    while(T--)
    {
        ans=-1;
        int x,y;
        for(int i=1;i<=5;i++)
        {
            scanf("%s",ch+1);
            for(int j=1;j<=5;j++)
            {
                if(ch[j]=='*')a[i][j]=2,x=i,y=j;
                else a[i][j]=ch[j]-'0';
            }
        }
        for(lim=1;lim<=15;lim++)
        {
            dfs(a,1,x,y);
            if(~ans)break;
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2018-11-23 18:34  LiGuanlin  阅读(210)  评论(0编辑  收藏  举报