POJ3723 Conscription , 最大权森林问题 ->最小生成树问题

本文详细阐述了并查集在处理构建不连通图时的问题,通过实例展示了错误使用可能导致的问题,并给出了正确的实现方式。通过具体的代码实现,深入浅出地介绍了如何在不连通的图中正确应用并查集,避免常见的陷阱。

http://poj.org/problem?id=3723

      这题虽然简单,但是还是错了很多次。

 因为这题构建的图可能是不连通的。也就是说可能有很多棵树。

所以我以前写的并查集用在这上面会出问题的。

while(x != f[x])

    x = f[x];

return f[x];

//我这样子每次用完之后并没有更新f[x]的值。

//虽然在连通图中没问题,但是在不连通的图里用就会有问题啦。大哭 血的教训。。。。

改正:

if(x !=f[x]) 

   f[x] = find(f[x]);

return f[x];

//============================================

code:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 20050;
const int maxm = 50050;
struct edge {
    int x, y, w;
    bool operator < (const edge& rhs) const {
        return w > rhs.w;
    }
};

edge es[maxm];
int f[maxn];
int n, m;

int Find(int x)
{
    if(x !=f[x])
        f[x] = Find(f[x]);
    return f[x];
}

int  kruskal() {
    int i, a, b;
    int ans = 10000*n;
    for(i=0; i<=n; ++i) f[i] = i;
    sort(es, es+m);
    for(i=0; i<m; ++i) {
        a = Find(es[i].x);
        b = Find(es[i].y);
        if(a!=b) {
            f[a] = b;
            ans -= es[i].w;
        }
    }
    return ans;
}
int main() {
    int N, M, R, i, t;
    scanf("%d",&t);
    while(t--) {
        scanf("%d%d%d",&N,&M,&R);
        n = N+M;
        m = R;
        for(i=0; i<m; ++i) {
            scanf("%d%d%d",&es[i].x, &es[i].y, &es[i].w);
            es[i].y  += N;
        }
        printf("%d\n", kruskal());
    }
    return 0;
}


Prim

int Prim()
{
    int i, j, p, ans, minc;
    memset(v, 0, sizeof v );
    for(i=0; i<=n; ++i) dis[i] = inf;
    dis[1] = 0;
    ans = 0;
    for(i=1; i<=n; ++i)
    {
        minc = inf, p = -1;
        for(j=1; j<=n; ++j) if(!v[j])
            if(minc>dis[j]) minc = dis[p=j];
        if(-1==p) break;
        v[p] = 1;
        ans += minc;
        for(j=0; j<G[p].size(); ++j)
        {
            pto &u = G[p][j];
            if(!v[u.to] && dis[u.to] > u.len)
            {
                dis[u.to] =u.len;
            }
        }
    }
    if(i==n+1)
        return ans;
    else
        return -1;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值