POJ-2157:Maze(特殊的bfs方式)


题目链接:点击打开链接


题目大意:

有一个迷宫,迷宫里面有对应的门,想通过门的话需要先找齐钥匙,注意钥匙可能不止一把。


解题思路:

刚看这道题的时候,感觉这道题和曾经做过的一道题很像,不过另外一道题每个门只有一把钥匙,利用状压储存状态做的。刚开始就往那方面想,但是发现钥匙的个数不确定根本没法确定状态。后来仔细看了一下,发现这道题是问最后能不能到终点,而不是到终点的最短步数,于是这道题就简单了许多。这也是这道题的关键,


解法我是用bfs写的,听说dfs也能写,这里主要说bfs。bfs的话就是先遍历所有你能到的点,在这个过程中,如果你碰到了某扇门,就将这扇门打个标记。等整个图没法走的时候,就开始在地图上暴力搜索,搜索在你打过标记的门中(注意一定是你打过标记的门)是否还有钥匙没拿到。如果钥匙都拿到了,就将这扇门的坐标加入队列。依次执行,最后判断是否能到达终点即可,注意这个题每种门只有一扇,所以也大大简化了解题过程,

这里的坑点主要有两点:

(1):在你遍历过程中达到过的门才可以被执行操作,

(2):注意整个图中可能存在没有钥匙但是却有这扇门的情况,题目虽然说至少一把钥匙,可能是想开门至少需要一把钥匙吧,也不太理解,不过这种情况是必须考虑的,整个图没有这个钥匙的话,这扇门是不能被通过的。

注意以上两点应该就没有太大问题了,不过个人觉得这个代码实现是真的恶心,细节看代码吧,


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <stack>
#include <set>
#include <functional>
#define rank ra
#define next ne
#define pb push_back
#define hash haha
#define xlson xl,xmid,xt<<1
#define xrson xmid+1,xr,xt<<1|1
#define ylson yl,ymid,xt,yt<<1
#define yrson ymid+1,yr,xt,yt<<1|1
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int INF=1e9+7;
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
char key[5]={'a','b','c','d','e'};  //钥匙种类
char doors[5]={'A','B','C','D','E'};    //门的种类
bool dv[5];     //记录门是否在之前bfs过程中被到达过
bool ke[5];     //记录地图是否存在该钥匙
struct node
{
    int x,y;
}door[5];       //记录各扇门的坐标
char ma[25][25];
bool vis[25][25];   //bfs标记数组
int n,m,sx,sy,ex,ey;
int flag;
bool check(int xx,int yy)   //判断当前点是否符合要求
{
    if(xx>=0&&xx<n&&yy>=0&&yy<m&&vis[xx][yy]==0&&ma[xx][yy]!='X')
    {
        for(int k=0;k<5;k++)
        {
            if(ma[xx][yy]==doors[k])    //如果能到达门 给该扇门打标记
            {
                dv[k]=1;
                return 0;
            }
        }
        return 1;
    }
    return 0;
}
void bfs()
{
    memset(vis,0,sizeof(vis));
    memset(dv,0,sizeof(dv));
    queue<node> que;
    node st;
    st.x=sx;st.y=sy;
    que.push(st);
    vis[sx][sy]=1;
    while(!que.empty())
    {
        node k1;
        node k=que.front();
        que.pop();
        if(k.x==ex&&k.y==ey)
        {
            flag=1;
            break;
        }
        for(int i=0;i<4;i++)
        {
            int xx=k.x+dx[i];
            int yy=k.y+dy[i];
            if(check(xx,yy))
            {
                k1.x=xx;k1.y=yy;
                que.push(k1);
                vis[k1.x][k1.y]=1;
            }
        }
        if(que.empty()) //如果无路可走 执行下面的操作
        {               //判断之前的门是否有可以开的
            int fl;
            for(int k=0;k<5;k++)
            {
                fl=1;
                for(int i=0;i<n;i++)
                {
                    for(int j=0;j<m;j++)
                    {
                        if(ma[i][j]==key[k]&&vis[i][j]==0)
                        {
                            fl=0;
                            break;
                        }
                    }
                }
                if(fl&&ke[k]&&dv[k]&&vis[door[k].x][door[k].y]==0)  //必须地图存在该钥匙且该扇门被到达过
                {
                    k1.x=door[k].x;
                    k1.y=door[k].y;
                    ma[k1.x][k1.y]='.';
                    vis[k1.x][k1.y]=1;
                    que.push(k1);
                }
            }
        }
    }
}
void init()     //预处理起点终点和门的坐标
{
    memset(ke,0,sizeof(ke));
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(ma[i][j]=='S')
            {
                sx=i;
                sy=j;
            }
            if(ma[i][j]=='G')
            {
                ex=i;
                ey=j;
            }
            for(int k=0;k<5;k++)
            {
                if(ma[i][j]==key[k])    //存在的钥匙打上标记
                    ke[k]=1;
                if(ma[i][j]==doors[k])
                {
                    door[k].x=i;
                    door[k].y=j;
                }
            }
        }
    }
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)
            break;
        for(int i=0;i<n;i++)
            scanf(" %s",ma+i);
        init();
        flag=0;
        bfs();
        if(flag)
            printf("YES\n");
        else
            printf("NO\n");
    }
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值