【题目大意】
有N个城市,N-1条路把这些城市连起来(刚好是一个树)。相邻的两个城市有一个运输容量C(i, j),而城市x到城市y的那条路的运输能力S取决与这条路上所经过的所有路中最小的那个容量。 以那一个城市为中心,到其他N-1个城市的运输能力总和最大?
【思路】
用神奇的并查集,把路按照权值从大到小排序,然后用类似Kruskal的方法不断的加入边。 对于要加入的一条路,这条路连接这城市x和y,x所在的集合为A, y所在的集合为B, 可以确定A,B集合内的所有路都比当前这条路的权值大。如果让集合B加入集合A,就是让中心城市位于集合A,那么可以确定这两个集合合并之后的总权值为: A的权值总和+B的数量*当前这条路的权值。同样算出让集合B加入集合A的情况,取两者合并后权值大的进行合并。
存在问题:1. 输出是long long 类型,那么特别注意乘法前面需要添加 longlong
long long a=allcost[proot]+(long long)nums[qroot]*cost;
2 注意区分nums和allcost数组。通过例子发现他们要取较大的。
#include<iostream>
#include<cstdio>
#include<set>
#include<vector>
#include<algorithm>
using namespace std;
#define MAX 200100
typedef struct {
int start;
int end;
int cost;
} Node;
Node d[MAX];
long long allcost[MAX]= {0};
int parent[MAX];
int nums[MAX];
long long allmax;
bool mycmp(Node a, Node b) {
return a.cost>b.cost;
}
int main() {
bool mycmp(Node a, Node b);
void uni(int p, int q,int cost);
int n;
while(scanf("%d",&n)==1) {
for(int i=0; i<n-1; i++) {
scanf("%d%d%d",&d[i].start,&d[i].end,&d[i].cost);
}
sort(d,d+n-1,mycmp);
for(int i=1; i<=n; i++) {
parent[i]=i;
allcost[i]=0;
nums[i]=1;
}
for(int i=0; i<n-1; i++) {
uni(d[i].start,d[i].end,d[i].cost);
}
cout<<allmax<<endl;
}
return 0;
}
int root(int p) {
if(p != parent[p]) {
parent[p] = root(parent[p]);
}
return parent[p];
}
void uni(int p, int q,int cost) {
int proot = root(p);
int qroot = root(q);
if(proot == qroot) return ;
long long a=allcost[proot]+(long long)nums[qroot]*cost;
long long b=allcost[qroot]+(long long)nums[proot]*cost;
// cout<<"------"<<p<<q<<a<<b<<endl;
if(a>b) {
parent[qroot] = proot;
allcost[proot]=a;
nums[proot]+=nums[qroot];
allmax=a;
} else {
parent[proot] = qroot;
allcost[qroot]=b;
nums[qroot]+=nums[proot];
allmax=b;
}
}