输入样例:
5
1 2 2
1 3 1
2 4 5
2 5 4
输出样例:
135
解题思路:
因为“从首都到达每个城市的距离都是唯一的”,所以由城市构成的图事实上是无环图,而无环图就是一棵树。
花费的路费为 10s + s(s +1) / 2 ,当距离s为有意义的正数时,路费是随着距离s单调递增的,所以求路费的最大值,就是求在两城市间距离的最大值。
在给定一棵树后,求树中长度最长的路径就是求树的直径。求树的直径分两步:①任取一点x,求其余点距离x最远的点y,此时的y就是树直径的一个端点。②求其余点距离y最远的点z,yz之间的距离即为树的直径。(可以通过抽象作图的方法证明)
因为图中点较稀疏,所以用邻接表建图。
找两城市的距离既可以用深搜,也可以用广搜,深搜时,因为图为双向图,为了避免结点被重复计算,即可以每次记录父结点,也可以用去重数组判断,每次将父结点的距离加上自身的距离;广搜时,将每个城市入队,用去重数组避免重复计算。
最坏情况下,当城市连成一条链时,距离为10^8,路费会爆int,需要用long存储。
Java代码:(dfs)
import java.util.*;
public class Main {
static ArrayList<Node> []city; // 邻接表
static int []dis; // 每个城市可以到达的最远距离
static class Node{
int x; // 城市编号
int w; // 距离
public Node(int x, int w) {
this.x = x;
this.w = w;
}
}
@SuppressWarnings("unchecked")
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
city = new ArrayList[n + 1]; // 用全局变量
dis = new int[n + 1];
for(int i = 1; i <= n; i++)
city[i] = new ArrayList<Node>();
for(int i = 0; i < n - 1; i++) {
int x = scan.nextInt(), y = scan.nextInt(), w = scan.nextInt();
city[x].add(new Node(y, w)); // 双向图
city[y].add(new Node(x, w));
}
scan.close();
dfs(1, -1, 0); // 找树的直径的一个端点
int index = 1;
for(int i = 1; i <= n; i++)
if(dis[index] < dis[i])
index = i;
Arrays.fill(dis, 0);
dfs(index, -1, 0); // 找最大距离
int s = 1;
for(int i = 1; i <= n; i++)
if(dis[i] > s) s = dis[i];
System.out.println(10 * s + (1l + s) * s / 2);
}
public static void dfs(int u, int pre, int d) { // 需要记录父结点
for(Node edge: city[u]) {
if(edge.x != pre) {
dis[edge.x] = d + edge.w;
dfs(edge.x, u, dis[edge.x]);
}
}
}
}
Java代码:(bfs)
import java.util.*;
public class Main {
static int n;
static ArrayList<Node> []city; // 数组中的每个元素都表示一条单链表
static int []dis;
static class Node{
int x, w;
public Node(int x, int w) {
this.x = x;
this.w = w;
}
}
@SuppressWarnings("unchecked")
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
city = new ArrayList [n + 1];
dis = new int[n + 1];
for(int i = 1; i <= n; i++)
city[i] = new ArrayList<>();
for(int i = 1; i < n; i++) {
int x = scan.nextInt(), y = scan.nextInt(), w = scan.nextInt();
city[x].add(new Node(y, w));
city[y].add(new Node(x, w));
}
scan.close();
bfs(1);
int index = 1;
for(int i = 1; i <= n; i++) // 找直径的一个端点
if(dis[index] < dis[i]) index = i;
Arrays.fill(dis, 0);
bfs(index);
int s = dis[1];
for(int i = 1; i <= n; i++)
if(s < dis[i]) s = dis[i];
System.out.println(10 * s + s * (s + 1l) / 2);
}
public static void bfs(int u) {
boolean []vis = new boolean[n + 1];
Queue<Integer> qu = new LinkedList<>(); // 队列中存放城市的编号
qu.add(u);
vis[u] = true;
while(!qu.isEmpty()) {
Integer num = qu.poll();
for(Node edge : city[num]) {
if(!vis[edge.x]) { // 避免重复遍历
qu.add(edge.x);
dis[edge.x] = dis[num] + edge.w;
vis[edge.x] = true;
}
}
}
}
}