题目链接: POJ 3669 Meteor Shower
题目大意:
你在坐标原点, 只能在第一象限沿着x,y轴方向移动, 单位时间内一次移动一格。马上将要迎来一场流星雨, 也只会落到第一象限, 每颗流行砸下来, 会毁掉它降落的位置以及直接相邻的上下左右四个位置。在某一块地区被流星摧毁后, 你不能再来这个地方。
一共有M颗流星, 每颗的坐标 Xi,Yi 以及降落时间 Ti 已知。
求你能到达安全地带的最短时间
题解:
求到达安全地带所需的最短时间, 容易想到用bfs。和走迷宫找最短路径不同的是, 这里的地图是随着时间变化的,因为不同流星落降落时间是不同的。
我的解法:首先,根据所有的流星的降落位置, 计算出最后状态的地图,记作 safe[][] , 这样就知道哪里是安全的, 哪里是不安全的。
先按照时间顺序给流星排个序,
然后, 每次宽搜,要在宽搜节点中加入一个时间属性。如果时间状态为 i 的节点都已经宽搜结束, 则需要更新地图的时间状态为i+1 , 然后在进行 i+1 的时间状态的搜索。
我用了一个 num[i] 数组来存放时间状态为 i <script type="math/tex" id="MathJax-Element-144">i</script> 的节点的个数。 num[i] 为0 时,则更新地图。用自己的方法AC之后, 找了别人的题解, 发现其实并不需要这样随着时间来更新地图, 可以用地图记录每个地方第一次被摧毁的时间。这样地图本身就有了时间属性。
代码:
#include <iostream>
#include <queue>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define MAXM 50010
#define MAXX 310
using namespace std;
struct Meteor {
int x, y, t;
}m[MAXM];
int M, ans;
int safe[MAXX][MAXX];
int map[MAXX][MAXX];
bool f[MAXX][MAXX];
int num[MAXM];
int fx[] = {0, 1, 0, -1};
int fy[] = {1, 0, -1, 0};
queue<Meteor> q;
bool cmp(const Meteor &a, const Meteor &b) {
return a.t < b.t;
}
//摧毁
void boom(int (*a)[MAXX], int x, int y) {
a[x][y] = 1;
a[x-1][y] = 1;
a[x][y-1] = 1;
a[x+1][y] = 1;
a[x][y+1] = 1;
}
bool is_safe(int x, int y) {
if (x > 0 && y > 0 && !safe[x][y]) return true;
else return false;
}
int bfs() {
memset(f, false, sizeof(f));
memset(num, 0, sizeof(num));
Meteor o = {1, 1, 0};
q.push(o);
int cnt = 0;
int p = 0;
f[1][1] = true;
num[0] = 1;
//更新0时间的地图
for (; m[p].t == cnt; p++) boom(map, m[p].x, m[p].y);
cnt++;
//更新1时间的地图
for (; m[p].t == cnt; p++) boom(map, m[p].x, m[p].y);
cnt++;
while (!q.empty()) {
Meteor a = q.front();
q.pop();
int x, y, t;
x = a.x; y = a.y; t = a.t;
if (is_safe(x, y)) {
return t;
}
for (int i = 0; i < 4; i++) {
int tx = x + fx[i];
int ty = y + fy[i];
if (0 < tx && 0 < ty && !map[tx][ty] && !f[tx][ty]) {
f[tx][ty] = true;
Meteor tmp = {tx, ty, t+1};
q.push(tmp);
num[t+1]++;
}
}
num[t]--;
if (!num[t]) {
//更新cnt时间的地图
for (; p < M && (m[p].t == cnt); p++) {
boom(map, m[p].x, m[p].y);
}
cnt++;
}
}
return -1;
}
int main() {
memset(safe, 0, sizeof(safe));
memset(map, 0, sizeof(map));
scanf("%d", &M);
for (int i = 0; i < M; i++) {
scanf("%d%d%d", &m[i].x, &m[i].y, &m[i].t);
m[i].x++; m[i].y++;
boom(safe, m[i].x, m[i].y);
}
sort(m, m+M, cmp);
ans = bfs();
printf("%d\n", ans);
return 0;
}