D - Medicines on Grid (atcoder.jp)
这是一道搜索题目,我们使用bfs来做,因为本题目没让你求最小路径,使用dfs也可以,这里使用bfs。
本题目核心思想如下:
小高要从起点到终点,要求其在能量大于等于0时到达终点,初始能量为0.
由于每走一个格子都需要一点能量,小高要到达终点势必需要去嗑药,那就涉及两个问题该如何去选择获取哪个药物,以及选择完药物后该如何行走的问题。在这里牵扯到一个格子可能由于去取得药物要走两次,所以单纯的bfs已经不合适,那我们考虑什么情况下一个格子要走两次?答案很显然,第二次经过这个格子时小高的能量比第一次高,只有如此才会使得走两次有意义。也只有这样才能保证最终的小高到达终点时的能量会尽可能的高也就保证小高尽可能的到达终点。在这里我们把visited数组改变他的含义,设置为小高在这一点的能量,只有比原先的高,才有可以走(visited详细说明:我们可以引入一点贪心的思想。我们可以将visit数组从bool型转为int型,存储目前到达它的路径中,到达它时血量最多的一次的血量。因为是bfs,所以简单的证明可以知道,如果一条路径到达一个已经到达过的点,且血量还小于等于visit时,那么即使完成了任务,其步数也不会时最优的。反之,如果到达一个点,其血量值可以更大,那么这就一种可能的路径,并不是重复到达。这样,就可以既保证了答案得正确性,又保证了不会TLE),这下我们的第二个问题路线结束了。第一个问题就交由bfs来解决。
接下来的是细节问题:
1:visited数组存储小高到达这一点时的能量,我们初始设置为-1。因为之后我们要使得到达这个点的能量最大才可以走这个点,如果设置为0,假如到达终点的时候能量恰好为0,那么我们在终点的上一个点能量为1,就无法向终点走了,因为终点的0并不大于visted数组,所以visited设置为-1.
2:第一次使用药物后,一定把药物设置为0,确保到达每一个格子的能量都大于等于0.
贴上代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.TreeMap;
import java.util.TreeSet;
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.security.PublicKey;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
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 IOException {
Scanner sc=new Scanner(System.in);
BufferedReader br1=new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw1=new PrintWriter(System.out);
String[] aStrings=br1.readLine().split(" ");
aa=Integer.parseInt(aStrings[0]);
bb=Integer.parseInt(aStrings[1]);
int a,b;
cc=new char[aa+1][bb+1];
yaowu=new int[aa+1][bb+1];
visited=new int[aa+1][bb+1];
int f;
for(a=1;a<=aa;a++) {
String aString=br1.readLine();
for(f=1;f<=bb;f++) {
cc[a][f]=aString.charAt(f-1);
}
}
String[] bStrings=br1.readLine().split(" ");
b=Integer.parseInt(bStrings[0]);
for(a=0;a<b;a++) {
String[] cStrings=br1.readLine().split(" ");
int c=Integer.parseInt(cStrings[0]);
int d=Integer.parseInt(cStrings[1]);
int e=Integer.parseInt(cStrings[2]);
yaowu[c][d]=e;
}
for(a=1;a<=aa;a++) {
for(b=1;b<=bb;b++) {
visited[a][b]=-1;
if(cc[a][b]=='S') {
cc[a][b]='.';
startx=a;
starty=b;
}
if(cc[a][b]=='T') {
cc[a][b]='.';
endx=a;
endy=b;
}
}
}
//System.out.println(startx+" "+starty+" "+endx+" "+endy);
dian d1=new dian(startx, starty, yaowu[startx][starty]);
visited[startx][starty]=yaowu[startx][starty];
ll1.add(d1);
while(ll1.size()!=0) {
dian d2=ll1.remove();
int x=d2.x;
int y=d2.y;
int blood=d2.blood;
//System.out.println(x+" "+y+" "+blood);
if(x==endx&&y==endy) {
System.out.println("Yes");
return;
}
for(int a1=0;a1<4;a1++) {
int x1=x+xx[a1];
int y1=y+yy[a1];
int blood1=blood-1;
if(x1>=1&&x1<=aa&&y1>=1&&y1<=bb&&cc[x1][y1]!='#'&&blood1>=0) {
if(blood1<yaowu[x1][y1]&&yaowu[x1][y1]!=0) {
blood1=yaowu[x1][y1];
yaowu[x1][y1]=0;
}
if(blood1>visited[x1][y1]) {
visited[x1][y1]=blood1;
ll1.add(new dian(x1, y1, blood1));
}
}
}
}
System.out.println("No");
}
public static int aa;
public static int bb;
public static char[][] cc;
public static int[][] yaowu;
public static int[][] visited;
public static int[] xx= {-1,1,0,0};
public static int[] yy= {0,0,-1,1};
public static LinkedList<dian> ll1=new LinkedList<>();
public static int startx,starty;
public static int endx,endy;
}
class dian{
int x;
int y;
int blood;
public dian(int x, int y, int blood) {
super();
this.x = x;
this.y = y;
this.blood = blood;
}
}