题意:一个特工要去取一个东西,每走一格需要1个单位时间,路上有监视器,监视器监视范围为两格,即所在格和方向格,并且每过一个单位时间会顺时针旋转90度;特工有隐身衣,可以无视监视器移动,但是这样每走一步需要3个单位时间。
思路:就是一个bfs,当移动的时候需要注意当前格和目标格在当前时间是不是被监视着,因为每走一步可能耗费的时间是1秒(正好当前不被监视)2秒(1秒后不被监视)3秒(2秒内一直被监视,直接用隐身衣走),所以还要用优先队列。
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
struct Node {
int cost, x, y;
Node() {}
Node(int a, int b, int c): x(a), y(b), cost(c){}
bool operator < (const Node &i) const {
return cost > i.cost;
}
};
char str[505][505], dir[] = "ESWN";
int d[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
int vis[505][505], n;
bool a[505][505][4];
int bfs(int cx, int cy) {
priority_queue<Node> pq;
Node node(cx, cy, 0);
pq.push(node);
for(int i = 0; i < 505; i++)
for(int j = 0; j < 505; j++)
vis[i][j] = 1 << 30;
while(!pq.empty()) {
node = pq.top(), pq.pop();
if(str[node.x][node.y] == 'T') return node.cost;
if(node.cost >= vis[node.x][node.y]) continue;
vis[node.x][node.y] = node.cost;
for(int i = 0; i < 4; i++) {
int x = node.x + d[i][0], y = node.y + d[i][1], sec = node.cost;
if(x < 0 || y < 0 || x >= n || y >= n || str[x][y] == '#') continue;
if(a[x][y][sec % 4] == false && a[node.x][node.y][sec % 4] == false) {
Node t(x, y, sec + 1);
pq.push(t);
}
else if(a[x][y][(sec + 1) % 4] == false && a[node.x][node.y][(sec + 1) % 4] == false) {
Node t(x, y, sec + 2);
pq.push(t);
}
else {
Node t(x, y, sec + 3);
pq.push(t);
}
}
}
return -1;
}
main() {
int t;
scanf("%d", &t);
for(int cas = 1; cas <= t; cas++) {
int cx, cy;
memset(a, 0, sizeof a);
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%s", str[i]);
for(int j = 0; str[i][j]; j++) {
if(str[i][j] == 'M') cx = i, cy = j;
for(int k = 0; k < 4; k++) {
if(str[i][j] == dir[k]) {
a[i][j][0] = a[i][j][1] = a[i][j][2] = a[i][j][3] = true;
for(int f = 0; f < 4; f++) {
int x = i + d[(f + k) % 4][0], y = j + d[(f + k) % 4][1];
if(x < 0 || y < 0 || x >= n || y >= n) continue;
a[x][y][f] = true;
}
break;
}
}
}
}
printf("Case #%d: %d\n", cas, bfs(cx, cy));
}
}