输入样例:
6 7 HZH
ROM 100
PKN 40
GDN 55
PRS 95
BLN 80
ROM GDN 1
BLN ROM 1
HZH PKN 1
PRS ROM 2
BLN HZH 2
PKN GDN 1
HZH PRS 1
输出样例:
3 3 195 97
HZH->PRS->ROM
算法思路:
这道题求了最短路大小,最短路条数,最大点权和,最少点数,路径的打印。
在dijkstra的更新距离时,依次处理,不重不漏。
其中路径打印模板:
Stack<Integer> st = new Stack<>(); // 路径是逆序的,压入栈 for(int i = endIdx; i != -1; i = pre[i]) // 打印路径 st.push(i);
对图中结点的处理:由于图中的顶点不是以标号的形式给出,需要先将字符串与标号一一映射,通过下标简化处理。
Java代码:
import java.io.*;
import java.util.*;
public class Main {
static int n, m, endIdx;
static final int N = 205, INF = 0x3f3f3f3f;
static String []name = new String[N];
static int []w = new int[N];
static int []dis = new int[N];
static int []cnt = new int[N]; // 最短路数量
static int []sum = new int[N]; // 点权和(总幸福感)
static int []num = new int[N]; // 经过的城市数量
static int []pre = new int[N]; // 路径
static boolean []vis = new boolean[N];
static int [][]g = new int[N][N];
static Map<String,Integer> map = new HashMap<>();
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]);
name[0] = split[2]; // 初始点为0
for(int i = 1; i < n; i++) {
split = br.readLine().split(" ");
name[i] = split[0];
if(split[0].equals("ROM")) endIdx = i;
w[i] = Integer.parseInt(split[1]);
}
for(int i = 0; i < n; i++) // 将所有的名字和序号对应
map.put(name[i], i);
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 = map.get(split[0]);
int b = map.get(split[1]);
g[a][b] = g[b][a] = Integer.parseInt(split[2]);
}
dijkstra();
}
public static void dijkstra() {
Arrays.fill(dis, INF);
Arrays.fill(pre, -1);
dis[0] = 0;
cnt[0] = 1;
for(int i = 0; i < n; i++) {
int t = -1;
for(int j = 0; j < n; j++)
if(!vis[j] && (t == -1 || dis[j] < dis[t]))
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];
cnt[j] = cnt[t];
sum[j] = sum[t] + w[j];
num[j] = num[t] + 1;
pre[j] = t;
}else if(dis[j] == dis[t] + g[t][j]) {
cnt[j] += cnt[t];
if(sum[j] < sum[t] + w[j]) { //幸福感
sum[j] = sum[t] + w[j];
num[j] = num[t] + 1;
pre[j] = t;
}else if(sum[j] == sum[t] + w[j] && num[j] > num[t] + 1) { //经过城市数
num[j] = num[t] + 1;
pre[j] = t;
}
}
}
}
System.out.println(cnt[endIdx] + " " + dis[endIdx] + " " + sum[endIdx] + " " + sum[endIdx] / num[endIdx]);
Stack<Integer> st = new Stack<>();
for(int i = endIdx; i != -1; i = pre[i]) // 打印路径
st.push(i);
while(st.size() != 1)
System.out.print(name[st.pop()] + "->");
System.out.print(name[st.pop()]);
}
}