题目地址:https://vjudge.net/problem/POJ-3669
倒霉蛋Bessie现在坐标原点(0,0),现在要有陨石砸下来,寻找Bessie到达安全地点(陨石砸不到的点)所需的最短时间。
此次共有M (1 ≤ M ≤ 50,000)颗流星来袭,流星i将在时间点Ti (0 ≤ Ti ≤ 1,000) 袭击点 (Xi, Yi) (0 ≤ Xi ≤ 300; 0 ≤ Yi ≤ 300)。每颗流星都将摧毁落点及其相邻四点的区域。
Bessie在0时刻时处于原点,且只能行于第一象限,以平行与坐标轴每秒一个单位长度的速度奔走于未被毁坏的相邻(通常为4)点上。在某点被摧毁的刹那及其往后的时刻,她都无法进入该点。
Input - 输入
第1行: 一个整数: M
第2..M+1行: 第i+1行包含由空格分隔的三个整数: Xi, Yi, and Ti
Output - 输出
仅一行: Bessie寻得安全点所花费的最短时间,无解则为-1。
样例:
Input:
4
0 0 2
2 1 2
1 1 2
0 3 5
Output:
5
分析:
0时刻 1时刻 2时刻 3时刻 4时刻 5时刻
(0,0)->(0,1)->(0,2)->(0,3)->(0,4)->(0,5)
->(1,3)->(1,4)
->(2,3)
5时刻的三个点是最近的安全点。在纸上画一下就能理解。
看到最短就想到bfs。最简单的地图只有两种状态,可达和不可达。
这题稍微复杂的是:
解决思路:
map
不用0、1来标记,而是用 int t
标记。-1代表安全,不会被陨石摧毁;t
代表在t
时刻被摧毁。map
标记为-1的点就是安全地点,即终点。细节见代码
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
class Point {
public int x, y, t;
public Point() {
}
public Point(int x, int y, int t) {
this.x = x;
this.y = y;
this.t = t;
}
}
public class Main {
private static final Scanner SC = new Scanner(System.in);
private static final int[] DX = {0, 0, -1, 1, 0};
private static final int[] DY = {-1, 1, 0, 0, 0};
private static int row = 303, col = 303; // 根据陨石坠落范围[0,300]设置地图范围,大一点点就可以,大太多也没用,因为求的是最短
private static int[][] map = new int[row][col];
/**
* 初始化地图
* 初始化值为-1,代表安全地点
*/
public static void initMap() {
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
map[i][j] = -1;
}
}
}
/**
* 记录陨石对地图的破坏情况
*/
public static void recordMeteor() {
int meteors = SC.nextInt();
int r, c, t, tr, tc;
// 记录陨石击中的时间
while (meteors-- > 0) {
// r,c为坐标
r = SC.nextInt();
c = SC.nextInt();
// t为陨石最早击中的时刻(最早摧毁时间)
// 部分地点会被重复摧毁,在该点被摧毁的刹那及其往后的时刻,都不能再到达,所以要保留最早摧毁时间
t = SC.nextInt();
// 陨石有溅射效果,落点和上下左右,共5个点都会被摧毁
for (int i = 0; i < 5; i++) {
tr = r + DX[i];
tc = c + DY[i];
// 陨石也有可摧毁的范围
if (tr < 0 || tr > 301 || tc < 0 || tc > 301) {
continue;
}
if (map[tr][tc] == -1) {
map[tr][tc] = t;
} else {// 保留最早被摧毁的时间
map[tr][tc] = Math.min(map[tr][tc], t);
}
}
}
}
public static int bfs() {
// 天胡,起点就是安全的
if (map[0][0] == -1) {
return 0;
}
// 反向天胡,没来及跑就被炸了
if (map[0][0] == 0) {
return -1;
}
Queue<Point> queue = new LinkedList<Point>();
queue.add(new Point(0, 0, 0));
while (!queue.isEmpty()) {
Point cur = queue.poll();
int tr, tc;
// 安全了,返回
if (map[cur.x][cur.y] == -1) {
return cur.t;
}
// 当前点不可达,抛弃这个状态
if (map[cur.x][cur.y] <= cur.t) {
continue;
}
// 当前点可达,但是还得跑
for (int i = 0; i < 4; i++) {
tr = cur.x + DX[i];
tc = cur.y + DY[i];
if (0 <= tr && tr < row && 0 <= tc && tc < col) {
// 下一步是安全地点
if (map[tr][tc] == -1) {
return cur.t + 1;
}
// 下一步可以到达,但是还得接着跑
if (cur.t < map[tr][tc]) {
// 把来时的路炸了,不走回头路
map[cur.x][cur.y] = cur.t;
queue.add(new Point(tr, tc, cur.t + 1));
}
}
}
}
return -1;
}
public static void main(String[] args) {
// 初始化地图
initMap();
// 记录陨石对地图的破坏情况
recordMeteor();
// bfs
int ans = bfs();
System.out.println(ans);
}
}
大佬们都是C/C++
java练习 bfs POJ_3669 Meteor Shower
原文:https://www.cnblogs.com/vastian/p/12783158.html