当前位置: 代码迷 >> 综合 >> NYOJ - 82 - 迷宫寻宝(一) (DFS)
  详细解决方案

NYOJ - 82 - 迷宫寻宝(一) (DFS)

热度:135   发布时间:2023-10-09 15:48:07.0

题目描述:

描述
一个叫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

题目思路:

1.从起点搜索,把能走的地方都走了(暂时所有的门都不能通过,即使有钥匙)。
2.当无路可走的时候,从能打开的门的坐标作为搜索起点继续搜索。
3.重复1-2直到找到终点G。
在数据输入的时候记录开门所需要的钥匙数量,在搜索过程中,更新这个数量。
在搜索过程中,要标记遇到过的门,因为即使找到钥匙,如果没找到门,同样打不开门。
在搜索过程中更新搜索到的门的坐标,而不是在数据输入过程中。因为可能有多个相同的门,比如A门有两个,如果在数据输入过程中记录的门的坐标位置的门没有在搜索过程中找到,但是找到了不同坐标的相同门,那么搜索就会出错。虽然说题目中明确说明“迷宫里有N个编过号的门(N<=5),它们分别被编号为A,B,C,D,E.”但是通过测试证明,测试数据中存在相同的门。做题的时候,不论题目说没说,最好还是考虑的周全一点比较好。

题目代码:

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream> 
using namespace std;
char maze[23][23];
int n, m, a, b, flag; 
struct doornum{int key, x, y;int meet;
}dn[5];
void check();void dfs(int x, int y){if(maze[x][y] != 'X'){if(maze[x][y] == 'G') {flag = 1;return ;} if(maze[x][y] >= 'a' && maze[x][y] <= 'e'){ // 钥匙 curk[maze[x][y] - 'a'] ++;dn[maze[x][y] - 'a'].key--;}if(maze[x][y] >= 'A' && maze[x][y] <= 'E'){ // 门 dn[maze[x][y] - 'A'].x = x; // 记录坐标 dn[maze[x][y] - 'A'].y = y;dn[maze[x][y] - 'A'].meet = 1; // 遇到标记 return ;}maze[x][y] = 'X'; // 已访问标记 dfs(x-1, y);dfs(x+1, y);dfs(x, y-1);dfs(x, y+1);	check(); // 遍历门,从能打开的门继续搜索 }
}void check(){for(int i = 0; i < 5; i++){		if(dn[i].meet == 1 && dn[i].key == 0){ // 判断是否遇见和是否能打开 maze[dn[i].x][dn[i].y] = 'X';dfs(dn[i].x-1,dn[i].y);dfs(dn[i].x+1,dn[i].y);dfs(dn[i].x,dn[i].y-1);dfs(dn[i].x,dn[i].y+1);	}}	
}int main(){while(scanf("%d%d",&n,&m)!=EOF && (m||n)){flag = 0;memset(maze,'X',sizeof(maze));memset(dn,0,sizeof(dn));for(int i = 1; i <= n; i++){for(int j = 1; j <= m; j++){cin>>maze[i][j];if(maze[i][j] == 'S'){ // 搜索起点 a = i; b = j;	}// 记录开门需要的钥匙数 if(maze[i][j] >= 'a' && maze[i][j] <= 'e'){dn[maze[i][j] - 'a'].key++;}				}}dfs(a,b);if(flag){printf("YES\n");}else{printf("NO\n");}}return 0;
}