hdu 3371 并查集+最小生成树

链接

http://acm.hdu.edu.cn/showproblem.php?pid=3371

解析


不同连通块的最小生成树,用并查集处理一个连通块,进行缩点。之后用最小生成树的prim算法即可。


代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include<queue>
#include <algorithm>
#include <map>
#include <set>
using namespace std;
const int maxn = 500+10;
const int maxe = 10000+10;
const int inf = 0x3f3f3f3f;
int fa[maxn], num[maxn];
int dis[maxn];
int vis[maxn];
int g[maxn][maxn];
int Find(int x) {
    return x==fa[x]?x:fa[x] = Find(fa[x]);
}

void Union(int u, int v) {
    int x = Find(u);
    int y = Find(v);
    if (x == y)
        return ;
    fa[y] = x;
    num[x] += num[y];
    num[y] = 0;
}


void init() {
    memset(g, inf, sizeof(g));
    memset(dis, inf, sizeof(dis));
    for (int i=1; i<=maxn ; i++){
        fa[i] = i;
        num[i] = 1;
        g[i][i] = 0;
    }
}
struct node {
    int u, v, w;
}p[25000+10];

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        int n, m, k;
        init();
        scanf("%d%d%d", &n, &m, &k);
        for (int i=0; i<m; i++) {
            int u, v, w;
            scanf("%d%d%d", &p[i].u, &p[i].v, &p[i].w);
        }

        for (int i=0; i<k; i++) {
            int t, u;
            scanf("%d%d", &t, &u);
            while (t > 1) {
                int v;
                scanf("%d", &v);
                Union(u, v);
                t--;
            }
        }

        for (int i=0; i<m; i++) {
            int u=Find(p[i].u), v=Find(p[i].v);
            int w = p[i].w;
            if (u != v) {
                g[v][u] = min(g[v][u], w);
                g[u][v] = min(g[u][v], w);
            }
        }
        for (int i=0; i<m; i++) 
            Union(p[i].v, p[i].u);
        int s = Find(1);
        if (num[s] != n) {
            puts("-1");
            continue;
        }
        dis[s] = 0;
        memset(vis, 0, sizeof(vis));
        int ans=0;
        for (int i=1; i<=n; i++) 
        {
            int minn = inf, mark = -1;
            for (int j=1; j<=n; j++)
            {
                if (minn > dis[j] && !vis[j]) {
                    minn = dis[j];
                    mark = j;
                }
            }
            if (mark == -1)
                break;
            ans += minn;
            vis[mark] = 1;
            for (int j=1; j<=n; j++)
                if (g[mark][j] < inf && !vis[j])
                dis[j] = min(dis[j], g[mark][j]);
        }
        printf("%d\n", ans);
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值