zoj3659(经典并查集)

这种思想很经典。 从最小的边选择,那么可以知道的是,在除去这条边的另外两个联通块,选其中一块中的点做为源点到另一块所得到的费用和。 如果你已经知道了这两个联通块内部选一个点时的最大费用和。那么这题就可以直接得到答案了,然后用递归思想独立的求这两块联通块。 

但是这样不好实现。 如果再反着想, 把边从大到小放入图中然后记录每个联通块的最大值。 然后就是合并的时候选择的问题了 。 

经典的思想,要好好记下 。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <map>
#include <queue>
#include <sstream>
#include <iostream>
using namespace std;
#define INF 0x3fffffff
#define N 200200
struct node
{
    int x,y,key;
}edge[N];

int n;
int bin[N];
long long mx[N],cnt[N];

int cmp(node t,node t1)
{
    return t.key>t1.key;
}

int get(int x)
{
    if(bin[x]==x) return x;
    return bin[x]=get(bin[x]);
}

int main()
{
    //freopen("C:\Users\Administrator\Desktop\in.txt","r",stdin);
    //freopen("C:\Users\Administrator\Desktop\in.txt","w",stdout);
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<=n;i++)
        {
            bin[i]=i;
            mx[i]=0;
            cnt[i]=1;
        }
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].key);
        }
        sort(edge+1,edge+n,cmp);
        long long ans=0;
        for(int i=1;i<n;i++)
        {
            int x,y;
            x=edge[i].x; y=edge[i].y;
            int a,b;
            a=get(x); b=get(y);
            if(mx[a]+edge[i].key*cnt[b] > mx[b]+edge[i].key*cnt[a])
            {
                mx[a]=mx[a]+edge[i].key*cnt[b];// 选a堆
                ans=max(ans,mx[a]);
                bin[b]=a;
                cnt[a]+=cnt[b];
            }
            else
            {
                mx[b]=mx[b]+edge[i].key*cnt[a]; //选b堆
                ans=max(ans,mx[b]);
                bin[a]=b;
                cnt[b]+=cnt[a];
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/chenhuan001/p/3354956.html