ZOJ 3659 题解

来源:互联网 发布:怎么让淘宝信誉高起来 编辑:程序博客网 时间:2024/06/06 09:23

转载请注明出处,谢谢http://blog.csdn.net/acm_cxlove/article/details/7854526       by---cxlove 

题目:给出一棵树,找出一个点,求出所有点到这个点的权值和最大,权值为路径上所有边权的最小值。

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3659 

比赛的时候卡了,一直往DP上想。

结果并查集搞定。

按边排序,从大到小插入,每条边将两个集合连起来,而新加的边是两个集合所有边最小的,那么两个集合中的点交叉的通路最小的边就是新加的,那只要枚举两个集合,a,b是a并入b更优还是b并入a更优就行了。集合内部点已经计算出,相互的只要知道集合中元素的个数就好了。

所以并查集只需要维护一个集合的元素个数,一个集合的总权值

    #include<cstdio>      #include<cstring>      #include<algorithm>      #define N 200100      using namespace std;      struct Edge{          int u,v,w;      }edge[N];      int f[N],num[N];      long long cost[N];      int find(int u){          if(f[u]==u)return u;          return f[u]=find(f[u]);      }      bool cmp(struct Edge a,struct Edge b){          return a.w>b.w;      }      int main(){          int n,i;          while(scanf("%d",&n)==1){              for(i=1;i<n;i++)                  scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].w);              sort(edge+1,edge+n,cmp);              for(i=1;i<=n;i++)f[i]=i,num[i]=1,cost[i]=0;              for(i=1;i<n;i++){                  int uu=find(edge[i].u);                  int vv=find(edge[i].v);                  if(uu!=vv){                      cost[vv]=max((long long)num[uu]*edge[i].w+cost[vv],(long long)num[vv]*edge[i].w+cost[uu]);                      num[vv]+=num[uu];                      f[uu]=vv;                  }              }              printf("%lld\n",cost[find(1)]);          }      }  


0 0
原创粉丝点击