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");
}
}