牛客练习赛40 B.小A与欧拉路

链接:https://ac.nowcoder.com/acm/contest/369/C
来源:牛客网

题目描述

小A给你了一棵树,对于这棵树上的每一条边,你都可以将它复制任意(可以为0)次(即在这条边连接的两个点之间再加一条边权相同的边),求所有可能新形成的图中欧拉路的最短长度
欧拉路:从图中任意一个点开始到图中任意一个点结束的路径,并且 图中每条边只通过恰好一次

输入描述:

第一行一个数 n ,表示节点个数
接下来 n-1 行,每行三个整数 u,v,w,表示有一条 u 到 v 边权为 w 的无向边
保证数据是一棵树

输出描述:

一行一个整数,表示答案
示例1

输入

复制
4
1 2 1
1 3 1
1 4 2

输出

复制
5

说明

一种可能的方案为复制 <1,2,1> 这条边一次,欧拉路为4->1->2->1->3

备注:

1n2×1051≤n≤2×105
1ui,vin1≤ui,vi≤n
1wi1041≤wi≤104


题解:容易得出,本题转化为求一条主链,所有支链上的边都复制一次,从主链上的端点沿主链前进,当某点上连有支链时,走到支链终点再走回该点。
   所以问题转化为要使得主链所占权值尽可能大,即求树的直径。
   最终结果ans = sgma{w×2}-直径上的权值。
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n;
 4 const int N = 200005;
 5 int head[N];
 6 struct Edge{
 7     int to,w,next;
 8 }edge[N*2];
 9 int tol;
10 typedef long long ll;
11 int ret;
12 bool vis[N];
13 int dis[N];
14 void init(){
15     tol = 0;
16     memset(head,-1,sizeof(head));
17 }
18 
19 void addedge(int u,int v,int w){
20     edge[tol] = Edge{v,w,head[u]};
21     head[u] = tol++;
22 }
23 
24 int bfs(int s){
25     memset(dis,0,sizeof(dis));
26     memset(vis,0,sizeof(vis));
27     queue<int> q;
28     q.push(s);
29     vis[s] = 1;
30     int len = 0;
31     while(!q.empty()){
32         int u = q.front();
33         q.pop();
34         for (int i = head[u];i != -1;i = edge[i].next){
35             int v = edge[i].to;
36             if (vis[v]) continue;
37             dis[v] = dis[u] + edge[i].w;
38             if (len < dis[v]){
39                 len = dis[v];
40                 ret = v;
41             }
42             vis[v] = 1;
43             q.push(v);
44         }
45     }
46     return len;
47 }
48 
49 int main(){
50     init();
51     scanf("%d",&n);
52     ll ans = 0;
53     for (int i = 0;i < n-1;++i){
54         int u,v,w;
55         scanf("%d%d%d",&u,&v,&w);
56         addedge(u,v,w);
57         addedge(v,u,w);
58         ans += w << 1;
59     }
60     bfs(1);
61     int v = bfs(ret);
62     printf("%lld\n",ans - v);
63     return 0;
64 }

猜你喜欢

转载自www.cnblogs.com/mizersy/p/10395714.html