hdoj-3085 Nightmare Ⅱ

考点

  • 双向BFS

题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <bits/stdc++.h>
using namespace std;
const int maxn = 8e2 + 50;
// 0~3上下左右
const int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};
char s[maxn][maxn];
bool M[maxn][maxn], G[maxn][maxn];
int r, c, ans;

struct node {
int x_, y_;
node(int x = 0, int y = 0) : x_(x), y_(y) {}
} m, g, z1, z2;
queue<node> mq, gq;

bool valid(int x, int y) {
if (x < 1 || y < 1 || x > r || y > c) return 0;
if (s[x][y] == 'X') return 0;
if (abs(x - z1.x_) + abs(y - z1.y_) <= 2 * ans) return 0;
if (abs(x - z2.x_) + abs(y - z2.y_) <= 2 * ans) return 0;
return 1;
}

void init() {
m = g = z1 = z2 = node(0, 0);
for (int i = 1; i <= r; ++i) {
for (int j = 1; j <= c; ++j) {
if (s[i][j] == 'M') {
m.x_ = i, m.y_ = j;
} else if (s[i][j] == 'G') {
g.x_ = i, g.y_ = j;
} else if (s[i][j] == 'Z') {
if (!z1.x_) {
z1.x_ = i, z1.y_ = j;
} else {
z2.x_ = i, z2.y_ = j;
}
}
}
}
ans = 0;
memset(M, 0, sizeof(M)), memset(G, 0, sizeof(G));
while (!mq.empty()) mq.pop();
while (!gq.empty()) gq.pop();
}

int bfs() {
int ms, gs;
mq.push(m), gq.push(g);
M[m.x_][m.y_] = G[g.x_][g.y_] = 1;
while (!mq.empty() || !gq.empty()) {
++ans;
for (int k = 1; k <= 3; ++k) {
ms = mq.size();
while (ms--) {
node u = mq.front();
mq.pop();
if (!valid(u.x_, u.y_)) continue;
for (int i = 0; i < 4; ++i) {
int x = u.x_ + dx[i], y = u.y_ + dy[i];
if (valid(x, y) && !M[x][y]) {
M[x][y] = 1;
mq.emplace(x, y);
}
}
}
}
gs = gq.size();
while (gs--) {
node u = gq.front();
gq.pop();
if (!valid(u.x_, u.y_)) continue;
for (int i = 0; i < 4; ++i) {
int x = u.x_ + dx[i], y = u.y_ + dy[i];
if (valid(x, y) && !G[x][y]) {
if (M[x][y]) return ans;
G[x][y] = 1;
gq.emplace(x, y);
}
}
}
}
return -1;
}

int main() {
int t;
cin >> t;
while (t--) {
cin >> r >> c;
for (int i = 1; i <= r; ++i) scanf("%s", (s[i] + 1));
init();
cout << bfs() << endl;
}
return 0;
}

思路

这道题最难的部分可能就是读题:

  • 鬼每次占领两步以内可达的点,无视墙;鬼占领区内的点也适用

  • 男每次走三步,女每次走一步

使用双向BFS,建立两个队列,分别从男、女的初始位置开始进行BFS,两边轮流进行。

在每一轮中,男孩BFS三次(模拟移动三步),女孩BFS一次(移动一步),分别用MG记录男、女的可达性。

每次扩展时,实时计算新状态与鬼之间的曼哈顿距离,如果距离小于等于当前轮数的2倍,那么不合法。

如果过程中G的点也出现在了M,当前轮数就是两人的最短会合时间。