题意: 有n个点n-1条边,现在规定i-j的路的最大负载量为i到j所经过的所有边的最小值,要求以某个点为中心然后求出这个中心点到所有点的负载量之和最大
思路: 并查集
分析:
1 n个点n-1条边很明显给定的这个关系就是一棵树
2 那么我们利用并查集,先对边按照权值从大到小排序,然后每一次在加入一条边的时候根据选择的中心点是在哪一个集合里面得到的和最大,那么我们就选择最大的那个,最后合并成一个集合答案就是随便一个点的根节点的rank值
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long int64; const int MAXN = 200010; struct Edge{ int x; int y; int val; bool operator<(const Edge& s)const{ return val > s.val; } }; Edge e[MAXN]; int n , father[MAXN] , num[MAXN]; int64 rank[MAXN]; void init(){ memset(rank , 0 , sizeof(rank)); for(int i = 1 ; i <= n ; i++){ father[i] = i; num[i] = 1; } } int find(int x){ if(x != father[x]) father[x] = find(father[x]); return father[x]; } int64 solve(){ sort(e , e+n-1); init(); for(int i = 0 ; i < n-1 ; i++){ int fx = find(e[i].x); int fy = find(e[i].y); //y连x int64 sum1 = (int64)e[i].val*(int64)num[fy]+rank[fx]; //x连y int64 sum2 = (int64)e[i].val*(int64)num[fx]+rank[fy]; if(sum1 > sum2){ father[fy] = fx; rank[fx] = sum1; num[fx] += num[fy]; } else{ father[fx] = fy; rank[fy] = sum2; num[fy] += num[fx]; } } return rank[find(1)]; } int main(){ while(scanf("%d" , &n) != EOF){ for(int i = 0 ; i < n-1 ; i++) scanf("%d%d%d" , &e[i].x , &e[i].y , &e[i].val); printf("%lld\n" , solve()); } return 0; }
时间: 2024-12-10 09:23:56