FZU 2180 骑士 (双向BFS)

Description

在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空位上。

给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步数完成任务。

Input

第一行有一个正整数T(T<=10) 表示一共有T组数据 接下来有T个5*5的矩形。0表示白色骑士1表示黑色骑士,*表示空位。(每组数据间有空行)

Output

对每组数据都输出一行。如果能在15不以内(包括15)到达目标状态,则输出步数,否则输出“Bored!”没有引号。

Sample Input

2
10110
01*11
10111
01001
00000

01011
110*1
01110
01010
00100

Sample Output

7
Bored!


分析:我们从当前进行状态搜索,只需要标记好状态就可以了。首先怎么标记状态:图为5*5,我们考虑用25位二进制表示。黑棋为1,白棋为0,‘*’的的权相当于0, 所以我们用一个int型变量就可以存下这个状态。同时记录'*'的位置,可以用一个值代替它的坐标即index=i*5+j(i,j为'*'的坐标0<=i,j<=4)。所以用map<pair<int,int>,int>映射,表示本状态,'*'位置,出现没。
题意告诉步数<=15,拿最坏的情况15步来说,我们要走15步,每次有8个状态,即8^15,即在队列里要存2^18个node型的数据,显然抄内存。
我们在考虑用双向bfs,正向:从给出的状态搜,反向:从最终的状态搜。 正搜和反搜的一步一步交替的,因此正搜和反搜的步数都不可能超过8。 正搜:在搜的过程中,判断此状态在反向中出现没,若出现则答案为两个状态的步数和。 反搜: 在搜的过程中,判断此状态在正向中出现没,若出现则答案为两个状态的步数和。 
代码:
#include<iostream>
#include<string>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<math.h>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int MAXN=7;
char maze[MAXN][MAXN];
int dir[8][2]={-1,2,-1,-2,-2,1,-2,-1,1,2,1,-2,2,1,2,-1};
struct node
{
    int x,y;
    int sta;
    int step;
    int indx;
    node(int xx=0,int yy=0,int ssta=0,int sstep=0)
    {
        x=xx;
        y=yy;
        sta=ssta;
        step=sstep;
        indx=x*5+y;
    }
    friend bool operator<(node xx,node yy)
    {
        return xx.sta<yy.sta;
    }
};
map<pair<int,int>,int>mp,mp1;
map<pair<int,int>,int>::iterator it;
struct node st,tx,ty;
int en,ind=12;
bool fun(queue<node>&Q,map<pair<int,int>,int>&MP,map<pair<int,int>,int>&MP1)
{//从此状态向8个方向搜索
        pair<int,int>p;
        tx=Q.front();
        Q.pop();
        if(tx.step>=9)
        {
            return false;
        }
        p=make_pair(tx.sta,tx.indx);
        if(MP1.find(p)!=MP1.end())
        {
            int ans=MP1[p]+tx.step;
            if(ans<=15)
            {
                printf("%d\n",MP1[p]+tx.step);return true;
            }
        }
        for(int i=0;i<=7;i++)
        {
            int xx=tx.indx/5+dir[i][0];
            int yy=tx.indx%5+dir[i][1];
            if(xx>=0&&xx<=4&&yy>=0&&yy<=4)
            {
                ty=tx;
                int temp=xx*5+yy;
                int flag=ty.sta&(1<<temp);
                if(flag)
                {
                    ty.sta-=1<<(temp);
                    ty.sta+=1<<(tx.indx);
                }
                ty.step=tx.step+1;
                ty.indx=temp;
                ty.x=xx;
                ty.y=yy;
                p=make_pair(ty.sta,ty.indx);
                if(MP.find(p)==MP.end())
                {
                    MP[p]=ty.step;
                    Q.push(ty);
                }
            }
        }

    return false;
}
void bfs()
{
    queue<node>q,q1;
    mp1.clear();//终状态
    pair<int,int>p;
    p=make_pair(en,ind);
    mp1[p]=1;
    q1.push( node(2,2,en,0));

    p=make_pair(st.sta,st.indx);//起始状态
    mp[p]=1;
    st.step=0;
    q.push(st);
    if(st.sta==en)
    {
        puts("0");return ;
    }
    while(!q.empty()&&!q1.empty())
    {
       bool ans = fun(q,mp,mp1);//正搜
       if(ans)return;
        ans=fun(q1,mp1,mp);//反搜
       if(ans)return;
    }
    puts("Bored!");
}
int main()
{
    int i,j,t,s;
    scanf("%d",&t);
    char ch[26];
    char str[6][6]={"11111","01111","00*11","00001","00000"};
    en=0;
    for(i=0;i<5;i++)
    {
        for(j=0;j<5;j++)
        if(str[i][j]=='1')
            en|=1<<(i*5+j);
    }
    while(t--)
    {
        s=0;
        mp.clear();
        for(i=0;i<5;i++)
        {
            scanf("%s",ch);
            for(j=0;j<5;j++)
            {
                if(ch[j]=='*')
                {
                    st.x=i;st.y=j;
                    st.indx=i*5+j;
                }
                if(ch[j]=='1')s|=(1<<(i*5+j));
            }
        }
        st.sta=s;
        bfs();
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值