P2895 [USACO08FEB] Meteor Shower S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
主要思路如下,
1:首先贝萨可以跑到牧场外,牧场牧场仅仅300*300那么大,
2:其次跑到牧场外不一定是最优解,可能牧场内某一点可能是最优的
整体思路是从起点的bfs,我们一开始记录一下所有会被陨石砸中的点,一旦我们bfs跑到一个点没被任何陨石砸中,那么我们就输出这个时间。同时我们要在每个时间段刷新一下下落的陨石,来判断这个格子能不能走。
来一波总思路吧
首先我们输入每个流星下落的地点和时间,把调用方法把所有可能会被变成不可走的点标记上,
接着我们把流行按照时间先后放入队列排好序。我们要知道我们要让流星先于我们一个时间单位坠落,也就是说我们在时间0的时候就要让时间1的流行陨落,为什么呢。你想呀,假如说你在时间0时走到了1号地点,现在时间为1了,这时我们在启动流星下落,万一流星下落到1号位置,你不就被砸死了吗,所以我们要在走前先把下一步流行落下。在开始走时,先落下0时辰的流行,在落1时间的流星。我们在落完流星后,我们开始往四周试探,如果这个点没被走过或者流星砸过,我们把它入优先队列的同时,判断一下他是不是最后的那个安全点,是就输出时间顺便把标记answer改为0,不是就接着走.记住流星不能超过牧场边界,而人可以,所以贝萨在走时没给他限制小于300。
最后如果answer始终没改变,那就证明贝萨没走出。输出-1
代码有注释:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.math.MathContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.TreeMap;
import java.util.TreeSet;
public class Main {
public static void main(String[] args) throws NumberFormatException, IOException {
Scanner sc=new Scanner(System.in);
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String[] aStrings=br.readLine().split(" ");
int a=Integer.parseInt(aStrings[0]);
int b;
for(b=0;b<a;b++) {//预处理
String[] bStrings=br.readLine().split(" ");
int c=Integer.parseInt(bStrings[0]);
int d=Integer.parseInt(bStrings[1]);
int e=Integer.parseInt(bStrings[2]);
ll1.add(new liuxing(c, d, e));
jieguo[c][d]=1;
chuliliuxing(c, d);//
}
Collections.sort(ll1);
LinkedList<liuxing> ll2=new LinkedList<>();
liuxing lx1=new liuxing(0, 0, 0);
ll2.add(lx1);
int f=0;
jiance(0);
visited[0][0]=1;
while(ll2.size()!=0) {
liuxing lx2=ll2.remove();
jiance(lx2.time+1);
int b1=lx2.x;
int c1=lx2.y;
int d1=lx2.time;
for(int a1=0;a1<4;a1++) {
int x1=xx[a1]+b1;
int y1=yy[a1]+c1;
if(x1>=0&&y1>=0&&visited[x1][y1]==0) {
visited[x1][y1]=1;
//System.out.println("AAA"+x1+" "+y1+" " +d1);
ll2.add(new liuxing(x1, y1, d1+1));
if(jieguo[x1][y1]==0) {
answer=0;
//System.out.println(x1+" "+y1);
System.out.println(d1+1);
return;
}
}
}
}
if(answer==Integer.MAX_VALUE) {
System.out.println("-1");
}
}
public static int answer=Integer.MAX_VALUE;
public static LinkedList<liuxing> ll1=new LinkedList<>();
public static int[][] jieguo=new int[350][350];//此数组记录最终被陨石点燃的点
public static int[][] visited=new int[350][350];//此数组记录按时间不可走的点
public static int[] xx= {-1,1,0,0};//四个方位
public static int[] yy= {0,0,-1,1};
public static void jiance(int a) {//此方法的作用是按照时间将四周的领域点燃来模拟流行下降的问题。
while(true) {
if(ll1.size()==0) {
break;
}
if(ll1.get(0).time!=a) {
break;
}
if(ll1.size()!=0) {
if(ll1.get(0).time==a) {
int c;
for(c=0;c<4;c++) {
int d=ll1.get(0).x+xx[c];
int e=ll1.get(0).y+yy[c];
if(d<0||d>300||e<0||e>300) {
continue;
}
visited[d][e]=1;
}
}
ll1.remove();
}
}
}
public static void chuliliuxing(int a,int b) {//主要记录流星下落后的点及其周围被点燃的点
int c;
for(c=0;c<4;c++) {
int d=a+xx[c];
int e=b+yy[c];
if(d<0||d>300||e<0||e>300) {//限制范围在农场之内。
continue;
}
jieguo[d][e]=1;
}
}
}
class liuxing implements Comparable<liuxing>{//流行类,主要记录流行下落的地点时间,并按时间排序
int x;
int y;
int time;
public liuxing(int x, int y, int time) {
super();
this.x = x;
this.y = y;
this.time = time;
}
@Override
public int compareTo(liuxing o) {
// TODO Auto-generated method stub
return this.time-o.time;
}
}