输入样例:
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
输出样例:
0 2 3 3 40
算法思路:
在dijkstra更新最短距离时,每更新一次距离,就修改pre数组值,并且修改花费;当原距离与待更新距离相等时,需要对比花费,当花费更小时需要更新,并记录pre数组值。
Java代码:
import java.io.*;
import java.util.*;
public class Main {
static int n, m, s, d;
static final int N= 505, INF = 0x3f3f3f3f;
static int [][]g = new int[N][N];
static int [][]w = new int[N][N];
static int []pre = new int[N]; // 记录上一步位置
static int []dis = new int[N];
static int []sum = new int[N]; // 记录最小花费
static boolean []vis = new boolean[N];
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] split = br.readLine().split(" ");
n = Integer.parseInt(split[0]);
m = Integer.parseInt(split[1]);
s = Integer.parseInt(split[2]);
d = Integer.parseInt(split[3]);
for(int i = 0; i < n; i++)
Arrays.fill(g[i], INF);
for(int i = 0; i < m; i++) {
split = br.readLine().split(" ");
int a = Integer.parseInt(split[0]);
int b = Integer.parseInt(split[1]);
int c = Integer.parseInt(split[2]);
int d = Integer.parseInt(split[3]);
g[a][b] = g[b][a] = Math.min(g[a][b], c);
w[a][b] = w[b][a] = d;
}
dijkstra();
System.out.println(dis[d] + " " + sum[d]);
}
public static void dijkstra() {
Arrays.fill(dis, INF);
dis[s] = 0;
Arrays.fill(pre, -2);
pre[s] = -1;
for(int i = 0; i < n; i++) {
int t = -1;
for(int j = 0; j < n; j++)
if(!vis[j] && (t == -1 || dis[t] > dis[j]))
t = j;
vis[t] = true;
for(int j = 0; j < n; j++) {
if(dis[j] > dis[t] + g[t][j]) {
dis[j] = dis[t] + g[t][j]; // 更新距离
sum[j] = sum[t] + w[t][j]; // 更新花费
pre[j] = t; // 记录位置
}else if(dis[j] == dis[t] + g[t][j]) {
if(sum[j] > sum[t] + w[t][j]) {
sum[j] = sum[t] + w[t][j]; // 更改花费
pre[j] = t; // 记录位置
}
}
}
}
int idx = d;
Stack<Integer> stack = new Stack<>();
stack.add(d);
while(pre[idx] != -1) { // 路径是反着的,先压入栈,再弹出
int t = pre[idx];
stack.add(t);
idx = pre[idx];
}
while(!stack.isEmpty())
System.out.print(stack.pop() + " ");
}
}