并查集+kruskal 模板

这篇博客原理讲得巨详细:算法学习笔记(1) : 并查集 - 知乎

本博客为上述文章的简洁版。

食用顺序:

判断类:1)初始化  2)按要求合并  3)查询是否在同一集合。

计算类:1)初始化  2)合并时计算

目录

路径压缩并查集

按秩合并并查集(使深度尽量小)

最小生成树——并查集版


路径压缩并查集

初始化

void init(int n)
{
    for (int i = 1; i <= n; ++i)
        fa[i] = i;
}

查询祖宗节点:将沿途每个节点的父节点设为根节点

int find(int x)
{
    return x == fa[x] ? x : (fa[x] = find(fa[x]));
}

合并

void merge(int i, int j)
{
    fa[find(i)] = find(j);
}

按秩合并并查集(使深度尽量小)

rank[]记录每个根节点对应的树的深度(如果不是根节点,其rank相当于以它作为根节点的子树的深度)。一开始,把所有元素的rank()设为1。合并时比较两个根节点,把rank较小者往较大者上合并。

初始化(按秩合并)

inline void init(int n)
{
    for (int i = 1; i <= n; ++i)
    {
        fa[i] = i;
        rank[i] = 1;
    }
}

合并(按秩合并)

inline void merge(int i, int j)
{
    int x = find(i), y = find(j);    //先找到两个根节点
    if (rank[x] <= rank[y])
        fa[x] = y;
    else
        fa[y] = x;
    if (rank[x] == rank[y] && x != y)
        rank[y]++;                   //如果深度相同且根节点不同,则新的根节点的深度+1
}

最小生成树——并查集版

首先我们把所有的边按照权值先从小到大排列,接着按照顺序选取每条边,如果这条边的两个端点不属于同一集合,那么就将它们合并,直到所有的点都属于同一个集合为止。

#include<bits/stdc++.h>
using namespace std;

const int maxn = 105;
const int maxm = 1050;

int n, m;
int par[maxn];
struct Edge {
    int from, to, dist;
}edges[maxm];

bool cmp(Edge x, Edge y) { return x.dist < y.dist; }
int find(int x) { return par[x] == x ? x : par[x] = find(par[x]); }
int kruskal() {
    int ans = 0;
    for (int i = 0; i < n; ++i) par[i] = i;
    sort(edges, edges + m, cmp);
    for (int i = 0; i < m; ++i) {
        Edge e = edges[i];
        int x = find(e.from);
        int y = find(e.to);
        if (x != y) { ans += e.dist; par[x] = y; }
    }
    return ans;
}

int main() {
    while (scanf("%d%d", &n, &m) == 2) {
        for (int i = 0; i < m; ++i) scanf("%d%d%d", &edges[i].from, &edges[i].to, &edges[i].dist);
        cout << kruskal() << endl;
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值