hdu 4424 Conquer a New Region(并查集)

本文讨论了HDU4424问题的解法,涉及树形DP、中心点选取及最大容量计算,提供了解题思路及关键代码片段。

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4424

题目大意:给你n个点,n-1条边,每个点有一个最大容量 c,要你找一个中心点,使它到其他 n-1 个点的最大容量的和最大,然后输出这个最大值。

思路:很好的一道题啊!因为对于每条边它有一个容量,一个点到另一个点的最大容量受这条路径里容量最小的那条边的容量的限制,所以这里我们考虑先将边的容量从大到小排序,然后一条一条边加进去,那么经过这条边有关系的点,肯定是以这条边为最小边的。现在考虑加进去一条容量为c的边,它连接了两个集合 A、B,如果选择是用 A 集合的中心点,那么就是 s = s_a+c*num_b,num_b 指的是B集合的点数,(*那里还有可能爆int,注意一下就行),选择 B 集合的也一样,然后比较确定一下就行了,再合并集合。如果加进去的这条边的两个端点已经是一个集合的了,那就直接continue,理由很简单,因为已经有一条更大的路径了。答案可能是超 int 的,用 lld 就行。

很容易想到它是一棵树,然后就会一直往树形DP上去想,然后就被坑死吧。。= =

代码如下:

#pragma comment(linker, "/STACK:10240000000000,10240000000000")
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int MAXN = 222222;

typedef __int64 lld;

struct Edge
{
    int s,t,c;
    bool operator < (const Edge &tmp) const
    {
        return c > tmp.c;
    }
} edge[MAXN];

int fa[MAXN];

int find_fa(int x)
{
    if(x == fa[x]) return x;
    return fa[x] = find_fa(fa[x]);
}

int num[MAXN];
lld sum[MAXN];

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        int tot = 0;
        for(int i = 1;i < n;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            edge[tot].s = a;
            edge[tot].t = b;
            edge[tot].c = c;
            tot++;
        }
        sort(edge,edge+tot);
        for(int i = 1;i <= n;i++)
        {
            fa[i] = i;
            num[i] = 1;
            sum[i] = 0;
        }
        for(int i = 0;i < tot;i++)
        {
            int a = edge[i].s;
            int b = edge[i].t;
            int c = edge[i].c;
            int fx = find_fa(a);
            int fy = find_fa(b);
            if(fx == fy) continue;
            lld s1 = sum[fx]+(lld)c*num[fy];
            lld s2 = sum[fy]+(lld)c*num[fx];
            //printf("%d,%d,%d,%d\n",fx,fy,s1,s2);
            if(s1 >= s2)
            {
                fa[fy] = fx;
                num[fx] += num[fy];
                sum[fx] = s1;
            }
            else
            {
                fa[fx] = fy;
                num[fy] += num[fx];
                sum[fy] = s2;
            }
        }
        //printf("%d\n",find_fa(1));
        lld ans = sum[find_fa(1)];
        printf("%I64d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值