HDU3085 Nightmare Ⅱ 题解

Description

link

Solution

这是个双向广搜板子题。

首先鬼的分裂实际上就是每一次走两步,由于没有障碍所以直接曼哈顿距离即可。
男孩每一次可以走 3 步,所以直接 bfs 连走 3 步即可。而女孩就只用走一步。

双向广搜需要用 2 个队列分别存储男孩和女孩的状态,不妨设这 2 个队列为 q0q_0q1q_1

处理答案时,就定义 step[0/1][x][y]step[0/1][x][y] 表示 (x,y)(x,y) 这个格点由 男孩/女孩 走到的最少次数,初始设为无穷大。
如果走了 ss 步且当前拓展的点以前有异性走过,那么就输出 ss 并停止 bfs。
如果 q0q_0q1q_1 均为空切没有停止 bfs 时,则男孩和女孩无法相遇,输出 1-1 即可。

这样做是 O(Tnm)O(Tnm) 的,有个很大的常数,并且这题 TT 非常大,需要注意一下常数。

Code

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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include <bits/stdc++.h>

#ifdef ORZXKR
#include <debug.h>
#else
#define debug(...) 114514
#endif

using namespace std;

const int kMaxN = 805, kInf = 0x3f3f3f3f;
const pair<int, int> dir[] = {{0, 1}, {0, -1}, {-1, 0}, {1, 0}};

struct Node {
int x, y, step;

Node() {}
Node(int _x, int _y, int _step) : x(_x), y(_y), step(_step) {}
~Node() {}
};

int T, n, m, ct;
int xx, xy, yx, yy;
int a[kMaxN][kMaxN], step[2][kMaxN][kMaxN];
string s;
char c[kMaxN][kMaxN];
pair<int, int> z[2];
queue<Node> q1, q2;

void init() {
while (!q1.empty()) q1.pop();
while (!q2.empty()) q2.pop();
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
step[0][i][j] = step[1][i][j] = kInf;
}
}
}

int get(int x, int y, int p) {
return abs(x - z[p].first) + abs(y - z[p].second);
}

bool check(int x, int y, int p) {
if (x < 1 || x > n || y < 1 || y > m || a[x][y] == 2) return 0;
if (get(x, y, 0) <= p * 2 || get(x, y, 1) <= p * 2) return 0;
return 1;
}

int bfs() {
init();
q1.emplace(Node(xx, xy, 0)), q2.emplace(Node(yx, yy, 0));
step[0][xx][xy] = step[1][yx][yy] = 0;
int st = 0;
while (!q1.empty() || !q2.empty()) {
int x, y; ++st;
if (!q1.empty()) {
for (int k = 0; k < 3; ++k) {
int m3, n3;
int kk = q1.size();
for (int hbq = 1; hbq <= kk; ++hbq) {
auto p1 = q1.front(); q1.pop();
x = p1.x, y = p1.y;
if (!check(x, y, st)) continue ;
for (auto d3 : dir) {
m3 = x + d3.first, n3 = y + d3.second;
if (!check(m3, n3, st) || step[0][m3][n3] != kInf) continue ;
q1.emplace(Node(m3, n3, st)), step[0][m3][n3] = st;
if (step[1][m3][n3] == kInf) continue ;
return st;
}
}

}

}
// =====================
if (!q2.empty()) {
int kk = q2.size();
for (int hbq = 1; hbq <= kk; ++hbq) {
auto p2 = q2.front(); q2.pop();
x = p2.x, y = p2.y;
if (!check(x, y, st)) continue ;
for (auto d : dir) {
int tx = x + d.first, ty = y + d.second;
if (!check(tx, ty, st) || step[1][tx][ty] != kInf) continue ;
q2.emplace(Node(tx, ty, st)), step[1][tx][ty] = st;
if (step[0][tx][ty] == kInf) continue ;
return st;
}
}

}
}
debug(step[0][5][3]);
return -1;
}

int main() {
scanf("%d", &T);
while (T--) {
ct = 0;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
scanf("%s", c[i] + 1);
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (c[i][j] == '.') {
a[i][j] = 1;
} else if (c[i][j] == 'X') {
a[i][j] = 2;
} else if (c[i][j] == 'M') {
a[i][j] = 1, xx = i, xy = j;
} else if (c[i][j] == 'G') {
a[i][j] = 1, yx = i, yy = j;
} else if (c[i][j] == 'Z') {
a[i][j] = 2, z[ct++] = {i, j};
} else {
assert(0);
}
}
}
printf("%d\n", bfs());
}
return 0;
}
/*
1
10 10
..........
..X.......
..M.X...X.
X.........
.X..X.X.X.
.........X
..XX....X.
X....G...X
...ZX.X...
...Z..X..X
*/

HDU3085 Nightmare Ⅱ 题解
https://sobaliuziao.github.io/2022/09/21/post/9c3d1486.html
作者
Egg_laying_master
发布于
2022年9月21日
许可协议