sincerit 82 迷宫寻宝(一)(多次BFS)

82 迷宫寻宝(一)
时间限制:1000 ms | 内存限制:65535 KB
难度:4
描述
一个叫ACM的寻宝者找到了一个藏宝图,它根据藏宝图找到了一个迷宫,这是一个很特别的迷宫,迷宫里有N个编过号的门(N<=5),它们分别被编号为A,B,C,D,E.为了找到宝藏,ACM必须打开门,但是,开门之前必须在迷宫里找到这个打开这个门所需的所有钥匙(每个门都至少有一把钥匙),例如:现在A门有三把钥匙,ACM就必须找全三把钥匙才能打开A门。现在请你编写一个程序来告诉ACM,他能不能顺利的得到宝藏。

输入
输入可能会有多组测试数据(不超过10组)。
每组测试数据的第一行包含了两个整数M,N(1<N,M<20),分别代表了迷宫的行和列。接下来的M每行有N个字符,描述了迷宫的布局。其中每个字符的含义如下:
.表示可以走的路
S:表示ACM的出发点
G表示宝藏的位置
X表示这里有墙,ACM无法进入或者穿过。
A,B,C,D,E表示这里是门,a,b,c,d,e表示对应大写字母的门上的钥匙。
注意ACM只能在迷宫里向上下左右四个方向移动。

最后,输入0 0表示输入结束。
输出
每行输出一个YES表示ACM能找到宝藏,输出NO表示ACM找不到宝藏。
样例输入
4 4
S.X.
a.X.
…XG

3 4
S.Xa
.aXB
b.AG
0 0
样例输出
YES
NO

这里要特么注意这一种情况,当第一次搜索到门的时候发现钥匙不够,然后在搜索搜索完剩下的地方后发现钥匙凑齐了,可是由于标记的原因无法再往搜过的地方再搜一遍了,例如这个例子:
3 3
S…
AX.
GXa
这样会一条路走到黑从而的到NO这样的答案
那要怎么办呢?
这就要进行多次搜索了
那什么时候是要多次搜索了?
当一次搜索完毕时发现现在手中的钥匙有增加,那就有可能现在凑齐了开门的钥匙,当发现钥匙没增加并且也到不了宝藏的位置,那说明已经把能搜的位置已经搜索完了,手中的钥匙打不开门了,这一定是到不了G点

#include <stdio.h>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
#define N 25
using namespace std;
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
struct node {
  int x, y;
};
char map[N][N];
int key[5];
int sumkey[5];
int m, n, sx, sy, gx, gy, flag;
int BFS(int x, int y) {
  int vis[N][N] = {0};
  node s, p;
  s.x = x; s.y = y;
  queue<node> que;
  que.push(s);
  while (que.size()) {
    node t = que.front();
    que.pop();
    if (map[t.x][t.y] == 'G') return 2;
    for (int i = 0; i < 4; i++) {
      p.x = t.x + dx[i];
      p.y = t.y + dy[i];
      if (p.x < 0 || p.x >= m || p.y < 0 || p.y >= n || map[p.x][p.y] == 'X')
        continue;
      if (vis[p.x][p.y]) continue;
      if (map[p.x][p.y] >= 'a' && map[p.x][p.y] <= 'e') {
        int k = map[p.x][p.y] - 'a';
        map[p.x][p.y] = '.';
        ++key[k]; // 搜集的钥匙 
        flag = 1;
      } else if (map[p.x][p.y] >= 'A' && map[p.x][p.y] <= 'E') {
        int k = map[p.x][p.y] - 'A';
        if (key[k] == sumkey[k]) map[p.x][p.y] = '.';
        else continue; // 打不开就不要标记放入队列了 
      }
      vis[p.x][p.y] = 1;
      que.push(p); 
    }
  }
  if (flag == 0) return -1;  // 搜索完毕钥匙没增加
  else return 1;  // 钥匙有增加
}
int main() {
  while (scanf("%d%d", &m, &n), m+n) {
    memset(sumkey, 0, sizeof(sumkey));
    memset(key, 0, sizeof(key));
    for (int i = 0; i < m; i++) {
      scanf(" %s", &map[i]);
      for (int j = 0; j < n; j++) {
        if (map[i][j] == 'S') {
          sx = i; sy = j;
        } else if (map[i][j] >= 'a' && map[i][j] <= 'e') {
          sumkey[map[i][j]-'a']++;
        }
      }
    }
    flag = 0;
    while (1) {
      flag = BFS(sx, sy);
      if (flag == 1) flag = 0; // 钥匙有增加,有找到宝藏的机会继续搜索 
      else if (flag == -1) break;  // 没钥匙打不开宝藏 
      else if (flag == 2) break;// 找到了宝藏 
    }
    if (flag == 2) printf("YES\n");
    else printf("NO\n"); 
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值