牛客练习赛40 B.小A与欧拉路
链接:https://ac.nowcoder.com/acm/contest/369/C
来源:牛客网
题目描述
小A给你了一棵树,对于这棵树上的每一条边,你都可以将它复制任意(可以为0)次(即在这条边连接的两个点之间再加一条边权相同的边),求所有可能新形成的图中欧拉路的最短长度
欧拉路:从图中任意一个点开始到图中任意一个点结束的路径,并且图中每条边只通过恰好一次
输入描述:
第一行一个数 n ,表示节点个数
接下来 n-1 行,每行三个整数 u,v,w,表示有一条 u 到 v 边权为 w 的无向边
保证数据是一棵树
输出描述:
一行一个整数,表示答案
备注:
1≤n≤2×1051≤n≤2×105
1≤ui,vi≤n1≤ui,vi≤n
1≤wi≤1041≤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 }