POJ - 1849 Two(树的直径)
题意:
给你N个结点的树,每条边的权值,以及一个起点位置S。 你有两个robot ,可以同时在树上跑。每跑过一条边就要花费一条边权值的油费(要重复i计算)。现在你要把整棵树跑完,问至少要花费多少。
思路:
做这道题的时候想到了之前做过19牛客暑期训练赛的一道题,第四场A-meeting(签到题),两个题都是给一颗树,然后求有关树的最小边权值。我们知道树的直径毫无疑问是最长的,我们既然要求最少花费即是对于长的路径我们要尽可能避免重复去跑。我们知道要遍历一棵树,分枝是会被重复跑而,枝干不会。所以我们选出树的直径作为枝干这样直径就只被跑一遍。重复跑的损失也就最小。
最后即 )ans = 所有边权值的和乘以2(重复跑)- 枝干的权值(没有重复跑)
code: (关于头文件部分,交的POJ 编译不了)然后把万能头换掉就行了,为了美观就用万能头....
#include<bits/stdc++.h> #define ll long long #define accept 0 using namespace std; const int maxm = 1e6+5; const int maxn = 1e5+5; const int inf = 0xffffff; struct edge{ int from; int to; int w; int next; }e[maxm]; int far; ll ans; int head[maxn]; int vis[maxn]; int dist[maxn]; int n,m,top; void add(int u,int v,int w){ e[top].from = u; e[top].to = v; e[top].w = w; e[top].next = head[u]; head[u] = top++; } void spfa(int s){ queue<int> q; for(int i = 1; i <= n ; i++) dist[i] = inf; memset(vis,false,sizeof(vis)); q.push(s); dist[s] = 0; while(!q.empty()){ int u = q.front() ; q.pop(); vis[u] = false ; for(int i = head[u] ; ~i ; i = e[i].next){ int v = e[i].to; if(dist[v] > dist[u] + e[i].w){ dist[v] = dist[u] + e[i].w; if(!vis[v]){ vis[v] = true; q.push(v); } } } } ans = 0; for(int i=1;i<=n;i++){ if(ans < dist[i]&&dist[i]!=inf){ ans = dist[i]; far = i; } } } void init(){ memset(head,-1,sizeof(head)); top =0; } ll sum; int main(){ init(); sum = 0; scanf("%d %d",&n,&m); for(int i=1;i<n;i++){ int u,v,w; scanf("%d %d %d",&u,&v,&w); sum += w; add(u,v,w); add(v,u,w); } int s = m; spfa(s); spfa(far); printf("%lld\n",sum*2-ans); return accept; }