【YBTOJ】【HDUOJ 3085】逃离噩梦
题目大意:
给定一张 \(N\times M\) 的地图,地图中有 \(1\) 个男孩,\(1\) 个女孩和 \(2\) 个鬼。
字符 .
表示道路,字符 X
表示墙,字符 M
表示男孩的位置,字符 G
表示女孩的位置,字符 Z
表示鬼的位置。
男孩每秒可以移动 \(3\) 个单位距离,女孩每秒可以移动 \(1\) 个单位距离,男孩和女孩只能朝上下左右四个方向移动。
在第 \(k\) 秒后所有与鬼的曼哈顿距离不超过 \(2\times k\) 的位置都会被鬼占领。
每一秒鬼会先扩展,扩展完毕后男孩和女孩才可以移动。
求在不进入鬼的占领区的前提下,男孩和女孩能否回合,若能回合,求出最短会和时间。
\(1<n,m<800\)。
正文:
双向 BFS 板子题。题目中的提示已经很足了。开两个队列分别搜男孩和女孩,就按着题目中给定的限制扩展即可。
代码:
const int N = 810;
inline int READ() {
int x = 0, f = 1; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -f; s = getchar(); }
while (s >= '0' && s <= '9') { x = x * 10 + s - '0'; s = getchar(); }
return x * f;
}
struct point
{
int x, y;
}bs, gs;
int n, m, gx1, gx2, gy1, gy2;;
char a[N][N];
int vis[N][N];
int dx[4] = {0, 1, 0, -1},
dy[4] = {1, 0, -1, 0};
queue <point> q, t;
bool ck(int x, int y, int k) {return x > 0 && x <= n && y > 0 && y <= m && a[x][y] != 'X' && a[x][y] != 'Z' && abs(x - gx1) + abs(y - gy1) > 2 * k && abs(x - gx2) + abs(y - gy2) > 2 * k;}
void bfs()
{
memset (vis, 0, sizeof vis);
while (!q.empty()) q.pop();
while (!t.empty()) t.pop();
q.push(bs), t.push(gs);
vis[bs.x][bs.y] = 1, vis[gs.x][gs.y] = 2;
for (int tim = 1; !q.empty() || !t.empty(); tim ++)
{
for (int j = 1; j <= 3; j++)
{
for (int k = q.size(); k--; )
{
point u = q.front();q.pop();
if (!ck(u.x, u.y, tim)) continue;
for (int i = 0; i < 4; i++)
{
int x = u.x + dx[i], y = u.y + dy[i];
if (!ck(x, y, tim)) continue;
if (vis[x][y] == 2)
{
printf ("%d\n", tim);
return;
}
if (vis[x][y]) continue;
vis[x][y] = 1;
q.push((point){x, y});
}
}
}
for (int k = t.size(); k--; )
{
point u = t.front();t.pop();
if (!ck(u.x, u.y, tim)) continue;
for (int i = 0; i < 4; i++)
{
int x = u.x + dx[i], y = u.y + dy[i];
if (!ck(x, y, tim)) continue;
if (vis[x][y] == 1)
{
printf ("%d\n", tim);
return;
}
if (vis[x][y]) continue;
vis[x][y] = 2;
t.push((point){x, y});
}
}
}
printf ("-1\n");
}
int main()
{
for(int t = READ(); t--; )
{
n = READ(), m = READ();
memset (a, 0, sizeof a);
gs = bs = (point){0, 0};
gx1 = gx2 = gy1 = gy2 = 0;
for (int i = 1; i <= n; i++)
{
scanf ("%s", a[i] + 1);
for (int j = 1; j <= m; j++)
{
if (a[i][j] == 'M') bs.x = i, bs.y = j;
if (a[i][j] == 'G') gs.x = i, gs.y = j;
if (a[i][j] == 'Z')
if (!gx1) gx1 = i, gy1 = j;
else gx2 = i, gy2 = j;
}
}
bfs();
}
return 0;
}