题目大意:给一个迷宫,骑士救公主,经过一个格子,耗费一个时间,路上有守卫,杀死守卫要耗费一个时间,也就是有守卫的格子要花费两个时间,求最短时间,如果不能,输出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; }