【BFS】迷宫寻宝(一)(nyoj-82)

题目链接点击打开链接

BFS题,看下NYOJ的讨论区,感觉数据挺变态。不过居然一遍就AC了......
好吧,个人觉得这题比较恼人的地方就是,一扇门需要集齐地图中的所有钥匙才能够打开。

这一点我刚写的时候没有仔细看(还以为是一把钥匙一扇门),结果对题目给的第二组测试数据纠结了很久.....

我的思路是:开一个key数组,在录入地图的时候,每逢a-e的钥匙出现,就计数+1;

在BFS过程中,每次遇到了一把钥匙,相应的计数就减去1,这样,当一把钥匙计数为0时,就代表着所有的钥匙都已经收集完全,可以打开对应的们了。

然而,有的钥匙由于被某一扇门阻隔,当前状态下无法收集,我们需要将别的门打开之后才能收集到。因此,判断当前状态下无法开启的们,未必在整个过程中都无法开启。因此,我们不能简单的在否定“入队”操作之后置之不理。

我的方法是将不能打开的们重新插入队尾。当然,为了防止死循环,必须先判断队列是否为空,如果队列为空,则表示该们无论如何都无法开启。

具体实现如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
char map[35][35];
bool visit[35][35];
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int key[5]={0};
int n,m;
struct node
{
       int i,j;
};
bool in_limit(node & in)
{
       if(in.i<1||in.j<1||in.i>n||in.j>m||visit[in.i][in.j])
              return false;
       char temp=map[in.i][in.j];
       if(temp=='X')
              return false;
       if(temp<='e'&&temp>='a')
              key[temp-'a']--;
       return true;
}
bool BFS(int si,int sj)
{
       node in,out;
       in.i=si;
       in.j=sj;
       queue<node>que;
       que.push(in);
       visit[in.i][in.j]=1;
       while(!que.empty())
       {
              out=que.front();
              que.pop();
              int tep=map[out.i][out.j];
              if(tep=='G')
                     return true;
              if(tep<='E'&&tep>='A')
              {
                     if(key[tep-'A']==0)
                     {
                            map[out.i][out.j]='.';
                     }
                     else
                     {
                            if(que.empty())
                                   return false;
                            else
                            {
                                   que.push(out);
                                   continue;
                            }
                     }
              }
              for(int i=0;i<4;i++)
              {
                     in.i=out.i+dir[i][0];
                     in.j=out.j+dir[i][1];
                     if(!in_limit(in))
                            continue;
                     visit[in.i][in.j]=1;
                     que.push(in);
              }
       }
       return false;
}

int main()
{
       while(scanf("%d%d",&n,&m)!=EOF&&(m||n))
       {
              getchar();
              memset(key,0,sizeof(key));
              int si,sj;
              memset(visit,0,sizeof(visit));
              for(int i=1;i<=n;i++)
                     for(int j=1;j<=m;j++)
                     {
                            cin>>map[i][j];
                            if(map[i][j]=='S')
                            {
                                   si=i;
                                   sj=j;
                            }
                            if(map[i][j]<='e'&&map[i][j]>='a')
                                   key[map[i][j]-'a']++;
                     }
              if(BFS(si,sj))
                     printf("YES\n");
              else
                     printf("NO\n");
       }
       return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值