关注我 一起刷完pat甲级题库
中文题面:
题目描述
作为城市的紧急救援团队负责人,你将获得一张你所在国家的特殊地图。
该地图显示了一些通过道路连接的分散城市,道路是双向的。
地图上标出了每个城市的救援队数量以及每对城市之间的每条道路的长度。
当其他城市发出紧急求援信息时,你的工作是尽快带领你的士兵前往该地点,同时,在途中尽可能多地调动救援帮手。
输入格式
第一行包含四个整数 N,表示城市数量(城市编号从 0 到 N−1),M 表示道路数量,C1 表示你当前所在的城市编号,C2 表示发出紧急求援信息的城市编号。
第二行包含 N 个整数,其中第 i 个整数表示城市 i 的救援队数量。
接下来 M 行,每行包含三个整数 c1,c2,Li,表示城市 c1 和城市 c2 之间存在一条道路相连,道路长度为 Li。数据保证 C1 和 C2 之间至少存在一条路径相连。
输出格式
共一行,两个整数,第一个整数表示 C1 和 C2 之间最短路的数量,第二个整数表示走最短路的情况下,能聚集到的救援队最大数量。
数据范围
2≤N≤500,
1≤M≤600,
1≤Li≤200,
每个城市包含的救援人员数量不超过 200。
思路
深度优先搜索,搜索过程中记录最短路的长度,条数,以及最短路所能集结的最大救援队数量,详见代码注释
AC代码
import java.util.*;
public class Main{
static int dest;//目的地
static boolean[] flag;//标记已经走过的城市,防止反复遍历
static int minroad=Integer.MAX_VALUE;//最短路的长度
static int res=0;//走最短路径能聚集到的救援队数量
static int[] value;//每个城市救援队的数量
static List<List<int[]>> list;//构建邻接表
static int countroad=0;//最短路的条数
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(),m=sc.nextInt(),curr=sc.nextInt();
dest=sc.nextInt();
flag=new boolean[n];
value=new int[n];
list=new ArrayList();
for(int i=0;i<n;i++){
value[i]=sc.nextInt();
list.add(new ArrayList());
}
for(int i=0;i<m;i++){
int a=sc.nextInt(),b=sc.nextInt(),c=sc.nextInt();
list.get(a).add(new int[]{b,c});//无向图,所以边是双向的
list.get(b).add(new int[]{a,c});
}
flag[curr]=true;//当前所在地已经到达
dfs(curr,0,value[curr]);//arg0 目前所在地 arg1 已走路的长度 arg2 救援队的数量
System.out.print(countroad+" ");
System.out.print(res);
}
public static void dfs(int curr,int road,int count){
if(road>minroad) return;//如果当前已走路已经长与最短路,则没必要搜索,直接return
if(curr==dest){//已经到到目的地且当前已走路的长度不大于已知的最短路
if(road<minroad){//如果比已知最短路更短
minroad=road;//更新最短路长度
res=count;//更新救援队数量
countroad=1;//最短路条数为1
}
else if(road==minroad){与已知最短路一样长
res=Math.max(count,res);//更新最大救援队数量
countroad++;//最短路长度不更新,最短路条数+1
}
}
else{//未到达目的地
for(int[] a:list.get(curr)){
if(flag[a[0]])//已经遍历过,无需再搜索
continue;
flag[a[0]]=true;//将该城市标记为已搜索
dfs(a[0],road+a[1],count+value[a[0]]);//继续搜索
flag[a[0]]=false;//回溯 当遍历完a城市 遍历下一个城市时 将a城市标记为未遍历
}
}
}
}