您的位置:首页 > 产品设计 > UI/UE

UVA 1664 - Conquer a New Region(并查集)

2015-08-24 21:13 274 查看
该题巧妙的运用了并查集,运用了类似于最小生成树算法的过程 ,通过该题可以对并查集有一个更深的理解 。

由于i和j唯一通路上容量的最小值为该两点的容量,求一个点到其他所有点的容量最大值 。

首先,解决两点的容量问题 ,我们将所有边从大到小排序,然后从大到小枚举,我们假设根结点就是要找的城市中心点,那么当又加入一条边时,该边的两个顶点所在的集合设为A、B,集合A、B的顶点a、b,要让谁当中心点呢? 易知:无论谁当中心点,它与另一个集合中任一点的容量都为该边长度(因为是从大到小枚举的)。

那么为了求出总容量,我们要维护一些值,用空间换时间 。 维护每个顶点的总容量sum[i],维护每个顶点与之相连的顶点数量,cnt[i],当前答案ans 。

那么对于a、b点,如果以a为中心,总容量为sum[a] + cnt[b] * e[i].c 。 反之亦然,哪个量大,则以哪个点为城市中心,也就是并查集的根结点 。

该题的巧妙之处在于,将答案结点维护成并查集的根结点,快速的找出一个集合中的城市中心 。

并查集用了路径压缩之后其实已经很快了,没有必要在改变树的高度,因为那样会改变根结点,不仅写起来麻烦,还丢掉了许多很好的特性 。

该题就是通过这些特性,维护一些重要的量以达到快速求解的目的 。 请读者细细品味 。

细节参见代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 200000 + 5;
int n,m,p[maxn];
ll sum[maxn],cnt[maxn];
struct Edge{
    ll a,b,c;
    bool operator < (const Edge& rhs) const {
        return c > rhs.c;
    }
}e[maxn];
int findd(int x) { return p[x] == x ? x : p[x] = findd(p[x]); }
ll solve() {
    for(int i=1;i<=n;i++) { p[i] = i ; sum[i] = 0 ; cnt[i] = 1; }
    ll ans = 0;
    sort(e,e+n-1);
    for(int i=0;i<n-1;i++) {
        int x = findd(e[i].a) , y = findd(e[i].b);
        ll suma = sum[x]+cnt[y]*e[i].c,sumb = sum[y]+cnt[x]*e[i].c;
        if(suma < sumb) {
            p[x] = y; sum[y] = sumb;
            cnt[y] += cnt[x]; ans = sum[y];
        }
        else {
            p[y] = x; sum[x] = suma;
            cnt[x] += cnt[y]; ans = sum[x];
        }
    }
    return ans;
}
int main() {
    while(~scanf("%d",&n)) {
        for(int i=0;i<n-1;i++) 
            scanf("%lld%lld%lld",&e[i].a,&e[i].b,&e[i].c);
        printf("%lld\n",solve());
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: