单点时限: 2.0 sec
内存限制: 256 MB
一天,sunny 不小心进入了一个迷宫,不仅很难寻找出路,而且有的地方还有怪物,但是 sunny 有足够的能力杀死怪物,但是需要一定的时间,但是 sunny 想早一点走出迷宫,所以请你帮助他计算出最少的时间走出迷宫,输出这个最少时间。
我们规定每走一格需要时间单位 1, 杀死怪物也需要时间 1, 如果不能走到出口,则输出 impossible. 每次走只能是上下左右 4 个方向。
输入格式
每次首先 2 个数 n,m (0<n,m≤200),代表迷宫的高和宽,然后 n 行,每行 m 个字符。
S 代码你现在所在的位置。
T 代表迷宫的出口。
代表墙,你是不能走的。
X 代表怪物。
. 代表路,可以走。
处理到文件结束。
输出格式
输出最少的时间走出迷宫。不能走出输出 impossible。
样例
输入样例:
4 4
S.X.
#..#
..#.
X..T
4 4
S.X.
#..#
..#.
X.#T
输出样例:
6
impossible
代码
// 稠密图使用邻接矩阵,稀疏图使用邻接表;
// 相比权值相等的走迷宫,其各权值不同,本质上是最短路径问题,因此不可使用是否标记来判断是否更新;
// --> dis存储到该节点的最短路径 + 优先队列存储最短距离对应的顶点。
#include <iostream>
#include <stdio.h>
#include <queue>
using namespace std;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}; // 上右下左 顺时针四个方向的矩阵偏移
struct node {
int x, y, dis;
};
bool operator < (const node & a, const node & b) {
return a.dis > b.dis;
}
const int N = 210;
char g[N][N];
int n, m;
typedef pair<int, int> PII;
struct node Prev[N][N];
void bfs(PII S, PII T){
int sx = S.first, sy = S.second, tx = T.first, ty = T.second;
priority_queue <node> heap; // 小项堆
heap.push({sx, sy, 0});
g[sx][sy] = '#';
while (!heap.empty())
{
node p = heap.top();
heap.pop();
if (p.x == tx && p.y == ty){
cout << p.dis << endl;
int x = tx, y = ty, d = p.dis;
while(x != sx || y != sy)
{
printf("(%d, %d, %d) <- ", x, y, d);
node t = Prev[x][y];
x = t.x, y = t.y, d = t.dis;
}
printf("(%d, %d, %d)", sx, sy, 0);
return;
}
for (int i = 0; i < 4; i ++)
{
int x = p.x + dx[i], y = p.y + dy[i];
if (x >= 1 && x <= n && y >= 1 && y <= m && g[x][y] != '#'){
struct node np {x, y, 0};
if (g[x][y] == 'X') np.dis = p.dis + 2;
// 此时下一顶点为终点时,既不为'.',也不为'X',但距离仍需要加一操作;因此直接使用if-else语句
else np.dis = p.dis + 1; // 两种情况:g[x][y] = '.' && g[x][y]为终点
g[x][y] = '#';
Prev[x][y] = {p.x, p.y, p.dis};
heap.push(np);
}
}
}
cout << "impossible" << endl;
}
int main(){
cin >> n >> m;
PII S, T;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++){
cin >> g[i][j];
if (g[i][j] == 'S')
S = {i, j};
if (g[i][j] == 'T')
T = {i, j};
}
bfs(S, T);
return 0;
}