题目大意:给一个迷宫,骑士救公主,经过一个格子,耗费一个时间,路上有守卫,杀死守卫要耗费一个时间,也就是有守卫的格子要花费两个时间,求最短时间,如果不能,输出Impossible。
分析:BFS。在遇到有守卫的格子时,不能直接加两个时间,而是要把这个格子当做两个格子来走。因为,这样得出最短路不一定是最短时间,比如,你正前方有三个守卫,你要走到正前方第四个格子,走直线的话,花费的时间就是7,假设旁边都没有守卫,你绕开走到的话,花费的时间仅为6。所以,拆成两个格子走了之后,现在的最短路就是真正的最短时间了。
代码:
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
const int maxn = 210;
int n, m, sr, sc;
char g[maxn][maxn];
int G[maxn][maxn];
int dr[4] = {0, 1, 0, -1};
int dc[4] = {1, 0, -1, 0};
struct Node {
int r, c, t;
Node(int r, int c, int t) : r(r), c(c), t(t) {}
};
int main() {
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &m, &n);
for(int i = 0; i < m; i++) {
scanf("%s", g[i]);
for(int j = 0; j < n; j++) {
if(g[i][j] == 'x') G[i][j] = 2;
else if(g[i][j] == '@' || g[i][j] == 'a') G[i][j] = 1;
else if(g[i][j] == 'r') G[i][j] = 0, sr = i, sc = j;
else G[i][j] = 0;
}
}
queue<Node> q;
q.push(Node(sr, sc, 0));
int ans = 1 << 30;
while(!q.empty()) {
Node p = q.front();
if(g[p.r][p.c] == 'a') {
ans = min(ans, p.t);
q.pop();
break;
}
if(g[p.r][p.c] == 'x' && G[p.r][p.c] == 1) { //在守卫的格子走第二步
q.push(Node(p.r, p.c, p.t+1));
G[p.r][p.c] = 0;
}
else {
for(int i = 0; i < 4; i++) {
int tr = p.r+dr[i];
int tc = p.c+dc[i];
if(tr >= 0 && tr < m && tc >= 0 && tc < n && G[tr][tc]) {
if(g[tr][tc] == 'x' && G[tr][tc] == 2) { //这里也就是拆格子的地方。在守卫的格子走第一步
q.push(Node(tr, tc, p.t+1));
G[tr][tc] = 1;
}
else if(g[tr][tc] != 'x'){
q.push(Node(tr, tc, p.t+G[tr][tc]));
G[tr][tc] = 0;
}
}
}
}
q.pop();
}
if(ans != 1 << 30) printf("%d\n", ans);
else printf("Impossible\n");
}
return 0;
}