SDUTOJ 2193 救基友3 用二进制作为第三维坐标的BFS

Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^

题目描述

  话说CZ由于不守基道,被妖怪抓走了,好基友WP在努力讨好高富帅RQ救出CZ的同时,CZ也意识到了自己的错误,然后努力的想逃出妖怪的闺房。 
   妖怪的闺房是一个n*m的矩阵,并且某些地方安装了带锁的门,钥匙藏在闺房另外的某些地方。刚开始WP被关在(sx,sy)的位置,离开闺房的门在(ex,ey)的位置。WP每分钟只能从一个坐标走到相邻四个坐标中的其中一个。妖怪每t分钟回闺房视察一次,若发现CZ不在原位置便把他再拎回去。经过若干次的尝试,CZ已画出整个闺房的地图。现在请你帮他计算能否再次成功逃亡。只要在妖怪下次视察之前走到出口就算离开闺房,如果妖怪回来的时候刚好走到出口或还未到出口都算逃亡失败。

输入

 每组测试数据的第一行有三个整数n,m,t(2<=n,m<=20,t>0)。接下来的nm列为闺房的地图,其中包括 :
代表路
代表墙
代表CZ的起始位置
代表闺房的出口
A-J 代表带锁的门,对应的钥匙分别为
a-j
a-j 代表钥匙,对应的门分别为A-J

每组测试数据之间有一个空行。

输出

 针对每组测试数据,如果可以成功逃亡,请输出最少需要多少分钟才能离开,如果不能则输出-1

示例输入

4 5 17
@A.B.
a*.*.
*..*^
c..b*

4 5 16
@A.B.
a*.*.
*..*^
c..b*

示例输出

16
-1


这个题很麻烦,但是思路很巧妙,不能用哈希来记录是否拿到了钥匙,而是用二进制的01来记录...

思路:用bfs搜索,不过标记变量需要注意一些问题。首先找到‘@’(起点),然后搜,遇到门判钥匙是否存在,存在的话放到队列里,不存在不放,遇到钥匙判是否存在,存在的话就不必收起来了,不存在的话就收起来。这里钥匙是不能单独存储的,因为你拿到钥匙后,有些以前不能去的地方你能去了,如第一组数据:你先搜到的是a,然后是A,你在搜到A判断是否有A的时候,就会是有,然后就会把A这个点的坐标放到队列里,这样就错了,因为你要先到a这个点,然后再回去遇到A才能把A放到队列里,再一个问题是就算是你走到a了,但是,二维数组已经标记过‘@’,因此,不会往回搜索了,所以,此题需要用一个三维标记数组来写。

二进制表示状态的办法:

如1,变成二进制是1,那么就代表A有相应的钥匙(a),如果是100(二进制),则代表有C的钥匙(c),怎么判断呢?用位运算,当然,你用二进制和十进制互换的那个算法也对。。。这里说二进制。。。判C的钥匙是否存在:

<span style="font-size:18px;">int a = 4;
int zh = 'C' - 'A';
int b = ((a >> zh) & 1);</span>

>> 是右移运算符,100(二进制)右移两位就是1,&是位与,真值情况和逻辑中的且是一样的,很明显,这里是1,也就是说b为1,(不会的学学位运算)。。。。。

把钥匙加入也要用到二进制位运算,还要用到位或(|),比如一开始什么钥匙都没有,突然遇到了d,然后加入就是:

int a = 0;
int zh = 'd' - 'a';
int b = ((1 << zh) | a);

1左移两位是1000(二进制,左移中没有的补0,比如110(二进制),左移一位就是1100(二进制)),然后取位或(|), 真值情况和逻辑中的或是一样的,很明显,这里是b用二进制是1000,换成十进制是8。


#include <stdio.h>
#include <ctype.h>
#include <string.h>

bool vis[1025][21][21];//这个数组是bfs的标记数组,多余的一维时用来记录是否含有某一把钥匙的
char mp[21][21];//地图记录

struct node
{
    int x;
    int y;
    int ans;
    int z;
}ls[8000010];//bfs中的队列

int bhx[] = {0,0,1,-1};
int bhy[] = {1,-1,0,0};//四个方向

bool pdys(int x,char c)//判断某个钥匙是否存在,第一个参数是目前存储钥匙是否存在的那个数的值,第二个参数就是判断这个门的钥匙是否存在
{
    int zh = c - 'A';
   return bool((x >> zh) & 1);
}

bool pdcz(int x,char c)//判断钥匙是否存在,这里是遇见了钥匙,上面是遇见了门
{
    int zh = c - 'a';
    return bool((x >> zh) & 1);
}

int sqys(int x,char c)//把钥匙收到手中,也就是变化存储钥匙的那个数
{
    int zh = c - 'a';
    return ((1 << zh) | x);
}

void bfs(int x,int y,int n,int m,int step)
{
    memset(vis,false,sizeof(vis));
    int tp = 0,tl = 0;
    node t,f;
    t.x = x;
    t.y = y;
    t.ans = 0;
    t.z = 0;
    ls[tp++] = t;
    vis[t.z][t.x][t.y] = true;
    while(tl < tp)
    {
        t = ls[tl++];
        if(mp[t.x][t.y] == '^')
        {
            if(t.ans < step)
                printf("%d\n",t.ans);
            else
                printf("-1\n");
            return ;
        }
        for(int i = 0;i < 4;i++)
        {
            f.x = t.x + bhx[i];
            f.y = t.y + bhy[i];
            f.z = t.z;
            f.ans = t.ans + 1;
            if(f.x >= 0 && f.x < n && f.y >= 0 && f.y < m \
               && !vis[f.z][f.x][f.y] && mp[f.x][f.y] != '*')
            {
                if(isupper(mp[f.x][f.y]))
                {
                    if(pdys(f.z,mp[f.x][f.y]))
                    {
                        ls[tp++] = f;
                        vis[f.z][f.x][f.y] = true;
                    }
                }
                else if(islower(mp[f.x][f.y]))
                {
                    if(!pdcz(f.z,mp[f.x][f.y]))
                    {
                        f.z = sqys(f.z,mp[f.x][f.y]);
                        ls[tp++] = f;
                        vis[f.z][f.x][f.y] = true;
                    }
                    else
                    {
                        ls[tp++] = f;
                        vis[t.z][f.x][f.y] = true;
                    }
                }
                else
                {
                    ls[tp++] = f;
                    vis[f.z][f.x][f.y] = true;
                }
            }
        }
    }
    printf("-1\n");//以前这里没加 总是错,后来问了问人家才知道,原来还有没有出口的情况,你说人家救个基友容易么????
}

int
 main()
{
    int n,m,step;
    while(~scanf("%d%d%d",&n,&m,&step))
    {
        for(int i = 0;i < n;i++)
        {
            scanf("%s",mp[i]);
        }
        for(int i = 0;i < n;i++)
        {
            int j;
            for(j = 0;j < m;j++)
            {
                if(mp[i][j] == '@')
                {
                    bfs(i,j,n,m,step);
                    break;
                }
            }
            if(j < m)
                break;
        }
    }
    return 0;
}





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值