最短路程

最短路程

给定一个 $n$ 个节点的树。

节点编号为 $1 \sim n$。

树中所有边均为双向边,且长度均已知。

你需要从 $1$ 号点出发,沿着一条路径遍历树中所有点,路径中可以包含重复的点和边。

要求,你的行程总长度应尽可能短。

请你计算,你所需的行程总长度的最小可能值。

注意,你可以在任意点结束你的行程。

输入格式

第一行包含整数 $n$。

接下来 $n−1$ 行,每行包含三个整数 $x,y,w$,表示点 $x$ 和点 $y$ 之间存在一条双向边,长度为 $w$。

输出格式

一个整数,表示行程总长度的最小可能值。

数据范围

前 $4$ 个测试点满足 $1 \leq n \leq 5$。
所有测试点满足 $1 \leq n \leq {10}^{5}$,$1 \leq x,y \leq n$,$0 \leq w \leq 2 \times {10}^{4}$。

输入样例1:

3
1 2 3
2 3 4

输出样例1:

7

输入样例2:

3
1 2 3
1 3 3

 

输出样例2:

9

 

解题思路

  从根节点开始走,最后必然会停在某个点上,当递归遍历到这个终点时,回溯的时候必然是沿着根节点到终点的路径回去。可以发现,从根节点到终点这条路径的每一条边都只用走一次,到达终点时虽然要回溯当从终点回溯到根节点的路径权值是不用累加的,而从根节点到其他结点回溯时需要把回溯过程中经过的路径权值累加。因此整个路径长度是由终点决定的,整个路径长度就是所有边的权值的两倍减去从起点到终点这条路径上的长度。由于所有边的权值的两倍是一个定值,因此要让整个路径长度最小,就要让从起点到终点这条路径上的长度最大。因此要求从根节点出发的最长路径。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 
 6 const int N = 1e5 + 10, M = N * 2;
 7 
 8 int head[N], e[M], wts[M], ne[M], idx;
 9 
10 void add(int v, int w, int wt) {
11     e[idx] = w, wts[idx] = wt, ne[idx] = head[v], head[v] = idx++;
12 }
13 
14 int dfs(int u, int pre) {
15     int maxd = 0;
16     for (int i = head[u]; i != -1; i = ne[i]) {
17         if (e[i] != pre) maxd = max(maxd, dfs(e[i], u) + wts[i]);
18     }
19     return maxd;
20 }
21 
22 int main() {
23     int n;
24     scanf("%d", &n);
25     memset(head, -1, sizeof(head));
26     LL s = 0;
27     for (int i = 0; i < n - 1; i++) {
28         int v, w, wt;
29         scanf("%d %d %d", &v, &w, &wt);
30         add(v, w, wt), add(w, v, wt);
31         s += wt << 1;
32     }
33     printf("%lld", s - dfs(1, -1));
34     
35     return 0;
36 }

 

参考资料

  AcWing 4706. 最短路程(AcWing杯 - 周赛):https://www.acwing.com/video/4499/

posted @ 2022-10-16 11:48  onlyblues  阅读(41)  评论(0编辑  收藏  举报
Web Analytics