并查集

基础并查集

1.  问题来源

一些不相交集合的合并和在集合中快速地查询的问题。举个例子,有一群人,他们之间有若干好友关系。如果两个人有直接或者间接好友关系,那么我们就说他们在同一个朋友圈中。随着时间的变化,这群人中有可能会有新的朋友关系,这时候我们会对当中某些人是否在同一朋友圈进行询问。

这个问题的解决方法很容易想到简单算法,大概思路是每个人用一个编号来表示他所在的朋友圈,如果有新认识的朋友,我们就合并朋友圈,即把两人的朋友圈中所有人编号标识成一样。 

 

接下来我们来大概的计算一下集合合并的时间复杂度,代码如下:

合并代码非常简单,那么可以看到一次合并的复杂度为O(n),一共有n个人,因此最多可能要合并n-1次,合并的复杂度为n^2,加上Q个朋友圈询问,那么总的复杂度就是O(n^2+Q)。当n很大的时候,算法是不可接受的。这个时候就该并查集出场了。

2.  相关定义与概念

并查集是一种支持合并集合和查找集合的树型数据结构,用于处理一些不相交集合的合并及查询问题,常常在使用中以森林来表示。

并查集主要有四步操作,第一步:Init();即初始化存放根节点数组

第二步:find_set(x);即找到x的根节点

第三步:union_set(x,y);判断x,y根节点是否相同,不同就让x的根节点连接y的根节点,使他们连通在一棵树上。

第四步:relation(x,y);判断x,y是否有关系,即根节点是否相同。

下面来举一个例子,还是上面刚刚讲到的朋友圈,我们这里假设朋友圈共有5个人。刚开始五个人互相不认识,因此可以看成五个只有一个结点的树,这个时候,如果1和2认识了,我们可以把1和2连接在一起,3和4认识了也可以同上相连接,当1和4认识的时候,我们找到1和4的根节点让他们相连接。


我们设存放父节点的数组为parent[],元素的编号是1-n.有m组集合关系。3.  伪代码实现

1. 首先我们要初始化存放父节点的数组,可依据如下算法:

(1)令i初值为1,i大于n时,算法结束,否则执行(2).

(2)令parent[i]的初始值为i,转(3).

(3)i的值加一,转(1).

2. 想要找到x元素的根节点,可依据如下算法:

(1)判断parent[x]是否等于x,是则返回x的值,否则执行(2).

(2)将parent[x]的值赋给x,执行(1).

3. 判断x,y要连接,可依据如下算法:

(1)x,y分别执行2.的操作找到根节点,判断x,y根节点是否相同,相同则算法结束,否则让x的根节点与y的根节点连接,然后算法结束.

4. 判断x,y是否有关系,可执行如下算法:

(1)x,y分别执行2.的操作找到根节点,判断x,y根节点是否相同,相同则返回true,否则然后返回false.

4.模板题讲解

 

HDU 1272 HowMany Tables

Problem Description

Today is Ignatius' birthday.He invites a lot of friends. Now it's dinner time. Ignatius wants to know howmany tables he needs at least. You have to notice that not all the friends knoweach other, and all the friends do not want to stay with strangers.

One important rule for this problem is that if I tell you A knows B, and Bknows C, that means A, B, C know each other, so they can stay in one table.

For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C canstay in one table, and D, E have to stay in the other one. So Ignatius needs 2tables at least.

Input

The input starts with aninteger T(1<=T<=25) which indicate the number of test cases. Then T testcases follow. Each test case starts with two integers N and M(1<=N,M<=1000).N indicates the number of friends, the friends are marked from 1 to N. Then Mlines follow. Each line consists of two integers A and B(A!=B), that meansfriend A and friend B know each other. There will be a blank line between twocases.

Output

For each test case, justoutput how many tables Ignatius needs at least. Do NOT print any blanks.

Sample Input

2

5 3

1 2

2 3

4 5

 

5 1

2 5

Sample Output

2

4

代码:

#include<stdio.h>

#include<string.h>

int parent[1002],n,m;

 

void Init()

{

    for(int i=0;i<=n;i++)

    {

       parent[i]=i;

    }

}

 

int find_set(int a)

{

    if(parent[a] == a) {

       returna;

    }

    else

    {

       return find_set(parent[a]);

    }

}

 

void union_set(intx,int y)

{

    int a=find_set(x);

    int b=find_set(y);

    if(a!=b)

    {

       parent[a]=b;

    }

}

 

int main()

{

    int T, x, y, cnt, i, j;

    scanf("%d", &T);

    while(T--)

    {

        cnt = 0;

        scanf("%d%d", &n,&m);

        Init();

        for(i=1;i<=m;i++)

        {

            scanf("%d%d", &x,&y);

            union_set(x,y);

        }

        for(i=1;i<=n;i++)

       {

           if(parent[i]==i)

           {

              cnt++;

           }

       }

        printf("%d\n",cnt);

    }

    return 0;

}

5.可供练习的题目

HDU    1213       How Many Tables       

HDU    1272       小希的迷宫          

HDU    1325       Is It A Tree?          

HDU    1856       More is better         

HDU    1232       畅通工程        

NYOJ   38         布线问题

 

6.算法延伸

1.基础并查集的优化

2.带权并查集

3.种类并查集

4. 异或并查集()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值