作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。
输入格式:
输入第一行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。
第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。
输出格式:
第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。
输入样例:
4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2
输出样例:
2 60
0 1 3
进阶dijkstra算法
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int n,m,s,d;
static int[][] tab; // 邻接矩阵
static int[] vis; // 标记是否被访问
static int[] pre; // 前驱节点
static int[] val; // 人数
static int[] dis; // 起始节点到各个节点的最短距离
static int[] pmax; // 起始节点到各个节点最大的人数
static int[] num; // 到达当前节点的最短路径有几个
static int inf = 999999;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
n = scan.nextInt(); // 城市的个数 0 ~ (N−1)
m = scan.nextInt(); // 快速道路的条数
s = scan.nextInt(); // S是出发地的城市编号
d = scan.nextInt(); // 目的地的城市编号
tab = new int[n][n];
vis = new int[n];
pre = new int[n];
val = new int[n];
dis = new int[n];
num = new int[n];
pmax = new int[n];
for (int i = 0; i < n; i++) {
Arrays.fill(tab[i], inf);
}
for (int i = 0; i < n; i++) {
val[i] = scan.nextInt();
}
for (int i = 0; i < m; i++) {
int a = scan.nextInt();
int b = scan.nextInt();
int w = scan.nextInt();
tab[a][b] = w;
tab[b][a] = w;
}
dijkstra(s);
System.out.println(num[d] + " " + pmax[d]);
print(d); // 打印到d的路径
}
public static void print(int v){
if (v == s) System.out.print(s);
else {
print(pre[v]);
System.out.print(" " + v);
}
}
private static void dijkstra(int v) {
vis[v] = 1;
for (int i = 0; i < n; i++) {
dis[i] = tab[v][i];
pre[i] = v;
// 直接相连的需要刚开始就更新pmax 并且 num 更新为 1
if (dis[i]!=inf) {
pmax[i] = val[v] + val[i];
num[i] = 1;
} else {
pmax[i] = val[i];
}
}
for (int i = 0; i < n-1; i++) {
int min = inf;
int ind = -1;
// 找未标记的中离start最近的 (贪心思想)
for (int j = 0; j < n; j++) {
if (vis[j] == 0 && dis[j] < min){
min = dis[j];
ind = j;
}
}
vis[ind] = 1; // 标记找到的节点
for (int j = 0; j < n; j++) {
if (vis[j] == 0 && dis[ind] + tab[ind][j] < dis[j]){
// 更新最短路径
dis[j] = dis[ind] + tab[ind][j];
// 更新前驱节点
pre[j] = ind;
// 更新 people Num
pmax[j] = pmax[ind] + val[j];
// 更新到当前路径最短的路的数量
num[j] = num[ind];
}else if (vis[j] == 0 && dis[ind] + tab[ind][j] == dis[j]){
// 当前这条路的min-num 是 开始到ind的num + 之前更新的num
num[j] += num[ind];
if (pmax[ind] + val[j] > pmax[j]){ // dis相同时比较pmax
pre[j] = ind;
pmax[j] = pmax[ind] + val[j];
}
}
}
}
}
}
dfs + dijkstra
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
public class Main {
static int n,m,s,d;
static int[][] tab; // 邻接矩阵
static int[] val; // 人数
static int[] vis; // vis标记
static List<Integer>[] pre; // 记录到当前节点的前一个节点(最短路径下)
static int inf = 999999;
static int[] dis; // 开始到当前节点的最小距离
static int maxNum = -1; // 开始到当前节点(最小距离条件下)最多的人数
static int ans = 0;
static List<Integer> path = new ArrayList<>();
static List<Integer> tmp = new ArrayList<>();
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
m = scan.nextInt();
s = scan.nextInt(); // start
d = scan.nextInt(); // end
tab = new int[n][n];
val = new int[n];
dis = new int[n];
vis = new int[n];
pre = new ArrayList[n];
for (int i = 0; i < n; i++) {
pre[i] = new ArrayList<>();
}
for (int i = 0; i < n; i++) {
Arrays.fill(tab[i],inf);
}
for (int i = 0; i < n; i++) {
val[i] = scan.nextInt();
}
for (int i = 0; i < m; i++) {
int a = scan.nextInt();
int b = scan.nextInt();
int w = scan.nextInt();
tab[a][b] = w;
tab[b][a] = w;
}
dijkstra(s);
dfs(d);
System.out.println(ans+" "+maxNum);
for (int i = path.size()-1; i >=1 ; i--) {
System.out.print(path.get(i) + " ");
}
System.out.println(path.get(0));
}
private static void dfs(int v) {
tmp.add(v);
if (v==s){
ans++;
int num = 0;
for (int i = 0; i < tmp.size(); i++) {
num += val[tmp.get(i)];
}
if (num > maxNum){
maxNum = num;
path.clear();
path.addAll(tmp);
}
tmp.remove(tmp.size()-1);
return;
}
for (int i = 0; i < pre[v].size(); i++) {
dfs(pre[v].get(i));
}
tmp.remove(tmp.size()-1);
}
private static void dijkstra(int v) {
vis[v] = 1;
for (int i = 0; i < n; i++) {
dis[i] = tab[v][i];
pre[i].add(v);
}
for (int i = 0; i < n-1; i++) {
int min = inf;
int ind = -1;
for (int j = 0; j < n; j++) {
if (vis[j]==0&&dis[j]<min){
ind = j;
min = dis[j];
}
}
vis[ind] = 1;
for (int j = 0; j < n; j++) {
if (vis[j]==0&&dis[ind]+tab[ind][j]<dis[j]){
pre[j].clear();
pre[j].add(ind);
dis[j] = dis[ind]+tab[ind][j];
}else if (vis[j]==0&&dis[ind]+tab[ind][j]==dis[j]){
pre[j].add(ind);
}
}
}
}
}