欢迎访问我的CCF认证解题目录
题目描述
思路过程
最短路径的变形题,首先要确保点到首都的最短距离不变,再去节省修路的费用,我们可以定义一个数组pre
保存上一个节点,当访问length[index]
时,length[pre[index]]
一定是已经访问过的了,修建时用sum += length[index] - length[pre[index]];
去计算。
代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader by = new BufferedReader(new InputStreamReader(System.in));
String[] line = by.readLine().split(" ");//读入行
int n = Integer.parseInt(line[0]), m = Integer.parseInt(line[1]);
long INF = Long.MAX_VALUE/2-1;//无限大
long sum = 0;
int[] pre = new int[n+1];//存储节点的上一节点
ArrayList<ArrayList<Node>> graph = new ArrayList<ArrayList<Node>>();
boolean[] flag = new boolean[n+1];
long[] length = new long[n+1];
for ( int i = 0; i <= n; i++ ) {
pre[i] = 1;//初始为1,首都
length[i] = INF;
graph.add(new ArrayList<Node>());
}
while ( m-- != 0 ) {
line = by.readLine().split(" ");
graph.get(Integer.parseInt(line[0])).add(new Node(Integer.parseInt(line[1]), Integer.parseInt(line[2])));
graph.get(Integer.parseInt(line[1])).add(new Node(Integer.parseInt(line[0]), Integer.parseInt(line[2])));
}
length[1] = 0;
while ( true ) {
int index = -1;
long min = INF;
//找最近的点
for ( int i = 1; i <= n; i++ ) {
if ( !flag[i] && length[i] < min ) {
min = length[i];
index = i;
}
}
if ( index == -1 ) break;
flag[index] = true;
sum += length[index] - length[pre[index]];//要修建的钱
//优化
for ( Node node: graph.get(index) ) {
if ( length[node.v] >= length[index] + node.length ) {
length[node.v] = length[index] + node.length;
if ( length[index] > length[pre[node.v]] ) {//如果能让后面的修建更短
pre[node.v] = index;
}
}
}
}
System.out.println(sum);
}
}
class Node {
int v;//点
long length;//长度
public Node(int v, long length) {
this.v = v;
this.length = length;
}
}