这是一道典型宽搜的题。
题目的注意点有很多:
300*300是流星的陨落范围,不是地图的大小。因此302是绝对的安全区域。
同一位置可能会有许多流星,这是应选择最早的那个进行状态标记。
t的范围是[0,1000],闭区间。所以存在刚开始就死在原点的可能性。(太惨了....)
同一队列中不同元素的时间可能是不同的,不能一概而论。
已访问过的点不必再访问。
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
const int MAXN = 300;
const int INF = 1500;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
int map[MAXN+3][MAXN+3];
struct P
{
int x;
int y;
int time;
P(int tx, int ty, int tt)
{
x = tx;
y = ty;
time = tt;
}
};
int Bfs()
{
queue<P> que;
int ans = -1;
que.push(P(302, 0, 0));
if (map[302][0] == 0)
return -1;
if (map[302][0] == INF)
return 0;
while (!que.empty()) {
P loc = que.front();
que.pop();
int i;
for (i = 0; i < 4; i++) {
int nx = loc.x + dx[i];
int ny = loc.y + dy[i];
if (nx >= 0 && nx < MAXN + 3 && ny >= 0 && ny < MAXN + 3
&& loc.time + 1 < map[nx][ny]) {
if (map[nx][ny] == INF) {
ans = loc.time + 1;
return ans;
}
que.push(P(nx, ny, loc.time+1));
map[nx][ny] = -1;
}
}
}
return -1;
}
int main()
{
for (int i = 0; i < MAXN + 3; i++) {
for (int j = 0; j < MAXN + 3; j++) {
map[i][j] = INF;
}
}
int m;
scanf("%d", &m);
for (int i = 0; i < m; i++) {
int x, y, time;
scanf("%d%d%d", &x, &y, &time);
int tmp = x;
x = MAXN + 2 - y;
y = tmp;
map[x][y] = min(map[x][y], time);
for (int j = 0; j < 4; j++) {
int nx = x + dx[j];
int ny = y + dy[j];
if (nx >= 0 && nx < MAXN + 3 && ny >= 0 && ny < MAXN + 3) {
map[nx][ny] = min(map[nx][ny], time);
}
}
}
printf("%d\n", Bfs());
return 0;
}
先将输入的坐标转换成我习惯的方式,在地图上用时间标记流星陨落范围。
搜索时将当前时间与地图上的时间比较即可。
若不是安全区域就将地图上的时间改成-1,避免重复访问。