题目描述
假设一个探险家被困在了地底的迷宫之中,要从当前位置开始找到一条通往迷宫出口的路径。迷宫可以用一个二维矩阵组成,有的部分是墙,有的部分是路。迷宫之中有的路上还有门,每扇门都在迷宫的某个地方有与之匹配的钥匙,只有先拿到钥匙才能打开门。请设计一个算法,帮助探险家找到脱困的最短路径。如前所述,迷宫是通过一个二维矩阵表示的,每个元素的值的含义如下 0-墙,1-路,2-探险家的起始位置,3-迷宫的出口,大写字母-门,小写字母-对应大写字母所代表的门的钥匙
输入描述
迷宫的地图,用二维矩阵表示。第一行是表示矩阵的行数和列数M和N
后面的M行是矩阵的数据,每一行对应与矩阵的一行(中间没有空格)。M和N都不超过100, 门不超过10扇
输出描述
路径的长度,是一个整数。
示例1
输入:
6 10
a110000011
0021111110
11101000A0
1001100111
100B000101
11030001b1输出: 33
算法分析
这题就是普通的bfs多了‘钥匙’这个状态
所以visit[x][y][key]的意义就是 横坐标为x,纵坐标为y,钥匙状态为key的点是否访问过
钥匙的状态 就用二进制数表示 最多10 把钥匙 那就是1024
比如我现在有第二把钥匙和第四把钥匙 那么我的钥匙状态就是 0101000000 也就是 320
BFS寻找最短路径:
#include<iostream>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<stdlib.h>
using namespace std;
int m, n;
int visit[105][105];
struct Node {
int x, y, step;
Node(int x, int y, int step) : x(x), y(y), step(step) {};
};
int bfs(vector<string> &str, int start_x, int start_y);
int main()
{
cin >> m >> n;
vector<string> str(m, string(n, ' '));
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
cin >> str[i][j];
bool flag = true;
for (int i = 0; i < m; ++i)
{
if (!flag) break;
for (int j = 0; j < n; ++j) {
if (str[i][j] == '2')
{
visit[i][j] = 1;
cout << bfs(str, i, j) << endl;
flag = false;
break;
}
}
}
}
int bfs(vector<string> &str, int start_x, int start_y)
{
queue<Node> que;
que.push(Node(start_x, start_y, 0));
vector<pair<int, int>> directs = { { 0, 1 },{ 0, -1 },{ 1, 0 },{ -1, 0 } };
while (!que.empty()) {
Node node = que.front();
que.pop();
if (str[node.x][node.y] == '3') return node.step;
for (pair<int, int> direct : directs) {
int x = node.x + direct.first;
int y = node.y + direct.second;
if (x < 0 || x >= m || y < 0 || y >= n || str[x][y] == '0') continue;
if (visit[x][y] != 1) {
visit[x][y] = 1;
que.push(Node(x, y, node.step + 1));
}
}
}
}
提交代码:
#include<iostream>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
using namespace std;
int m, n;
int visit[105][105][1200] ;
struct Node {
int x, y, key, step;
Node(int x, int y, int key, int step) : x(x), y(y), key(key), step(step) {};
};
int bfs(vector<string> &str, int start_x, int start_y);
int main()
{
cin >> m >> n;
memset(visit, 0, sizeof(visit));
vector<string> str(m, string(n, ' '));
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
cin >> str[i][j];
bool flag = true;
for (int i = 0; i < m; ++i)
{
if (!flag) break;
for (int j = 0; j < n; ++j) {
if (str[i][j] == '2')
{
visit[i][j][0] = 1;
cout << bfs(str, i, j) << endl;
flag = false;
break;
}
}
}
return 0;
}
int bfs(vector<string> &str, int start_x, int start_y)
{
queue<Node> que;
que.push(Node(start_x, start_y, 0, 0));
vector<pair<int, int>> directs = { { 0, 1 },{ 0, -1 },{ 1, 0 },{ -1, 0 } };
while (!que.empty()) {
Node node = que.front();
que.pop();
if (str[node.x][node.y] == '3') return node.step;
for (pair<int, int> direct : directs) {
int x = node.x + direct.first;
int y = node.y + direct.second;
int key = node.key;
if (x < 0 || x >= m || y < 0 || y >= n || str[x][y] == '0') continue;
// 捡钥匙
if (str[x][y] >= 'a' && str[x][y] <= 'z') key |= (1 << (str[x][y] - 'a'));
// 如果没带这扇门的钥匙,就不能通过A点
if (str[x][y] >= 'A' && str[x][y] <= 'Z' && (key & (1 << (str[x][y] - 'A'))) == 0) continue;
// 是否带着某些钥匙走过(因此可以走回头路,但前提是去拿钥匙)
if (visit[x][y][key] != 1) {
visit[x][y][key] = 1;
que.push(Node(x, y, key, node.step + 1));
}
}
}
return 0;
}