HDU

来源:互联网 发布:seo点击软件 编辑:程序博客网 时间:2024/05/29 17:20

思路:类似Kruskal算法,将边按权值从大到小排序,每次加入一条边AB,如果以A所在的集合为中心城市,那么总权值为A所在集合的权值加上B所在集合点的数量乘以这条边的权值,因为A、B所在集合中的边肯定大于AB的权值,如果B所在的集合为中心城市,可以以同样的方法计算,取两者中大的那一个。

#include<cstdio>#include<set>#include<algorithm>#include<cstring>#include<iostream>#include<map>#include<queue>#include<vector>#include<stack>#include<string>#include<sstream>#include<set>#include<cmath>using namespace std;const int INF = 0x3f3f3f3f;const int maxn = 2e5 + 20;const double EPS = 1e-5;const int mod = 1e9 + 7;typedef unsigned long long ull;typedef long long LL;int dx[] = {0, 0, -1, 1, -1, -1, 1, 1};int dy[] = {1, -1, 0, 0, -1, 1, -1, 1};struct Edge{    int from, to, c;    bool operator <(const Edge& rhs) const{        return c > rhs.c;    }}a[maxn];struct Node{    LL sum;    int num;}b[maxn];int f[maxn];int Find(int x){    return x == f[x] ? x : f[x] = Find(f[x]);}int main(){    int n;    while(scanf("%d", &n) == 1){        for(int i = 0; i < n - 1; ++i){            scanf("%d%d%d", &a[i].from, &a[i].to, &a[i].c);        }        sort(a, a + n - 1);        for(int i = 1; i <= n; ++i) f[i] = i;        for(int i = 1; i <= n; ++i){            b[i].num = 1;            b[i].sum = 0;        }        for(int i = 0; i < n - 1; ++i){            int t1 = Find(a[i].from), t2 = Find(a[i].to);            if(b[t1].sum + (LL)b[t2].num * (LL)a[i].c > b[t2].sum + (LL)b[t1].num * (LL)a[i].c){                f[t2] = t1;                b[t1].num += b[t2].num;                b[t1].sum = b[t1].sum + (LL)b[t2].num * (LL)a[i].c;            }            else{                f[t1] = t2;                b[t2].num += b[t1].num;                b[t2].sum = b[t2].sum + (LL)b[t1].num * (LL)a[i].c;            }        }        printf("%lld\n", b[Find(1)].sum);    }}/*3 33 1 23 2 02 3 2*/


原创粉丝点击