并查集

来源:互联网 发布:mac 查看文件内容命令 编辑:程序博客网 时间:2024/05/29 01:56

功能

1、实现两个集合的合并2、查询一个元素属于哪个集合

实现

一共两个函数:1、查找当前元素a,属于哪个集合 :int getPar(int a)注意实现时需要做路径压缩,下图就是路径压缩的原理:![这里写图片描述](http://img.blog.csdn.net/20160823214627924)函数实现:int getPar(int a){    if(par[a] == a)        return a;    return par[a] = getPar(par[a]);}原理:par[a] = a;即当前集合的跟就是自己,即可返回;如果不是那么:要做的是getPar(par[a]),即递归的找根,此处我有时会傻逼写成getPar[a] 如果写成这种,就死循环了。递归要每次都进一步,如上图:即d的父亲不是d而是c,那么要找的是c的父亲才能一直向上递归。然后把当前的par[a] = getPar[a]即可实现路径压缩。

2、集合的合并此处简单,原理如下:![这里写图片描述](http://img.blog.csdn.net/20160823214654932)函数实现:void mergePar(int a,int b){    par[getPar(a)] = getPar(b);//a接到b上}即将a找到根节点后,将根节点的父亲置为b的根节点编号

效率

getPar的时间复杂度:(此处暂时未弄清楚)![这里写图片描述](http://img.blog.csdn.net/20160823214741018)

例题

poj 1611 http://poj.org/problem?id=1611n个学生分属m个团体,(0 < n <= 30000 , 0 <= m <= 500) 一个学生可以属于多个团体。 一个学生疑似患病,则它所属的整个团体都 疑似患病。已知0号学生疑似患病,以及每个 团体都由哪些学生构成,求一共多少个学生 疑似患病。 

题解

#include <iostream>using namespace std;const int maxn = 30100;int par[maxn];void initPar(int n){    for (int i = 0; i <= n; ++i) {        par[i] = i;    }}int getPar(int a){    if(par[a] == a)        return a;    return par[a] = getPar(par[a]);}void mergePar(int a,int b){    par[getPar(a)] = getPar(b);//a接到b上}int n,m,total;int main() {    while (scanf("%d %d",&n,&m)){        if(n ==0 && m == 0) break;        initPar(n);        total = 0;        int nloop, tmp,tmp1;        while (m--){            scanf("%d",&nloop);            scanf("%d",&tmp1);            nloop--;            while (nloop--){                scanf("%d",&tmp);                mergePar(tmp,tmp1);                tmp1 = tmp;            }        }        while (n--){            if(getPar(n) == getPar(0))                total++;        }        printf("%d\n",total);    }    return 0;}
0 0
原创粉丝点击