并查集(入门讲解)

并查集

所谓并查集,类似于找朋友
现在有一群人(总共n个人),两两之间组成了朋友。
而且朋友的朋友也是自己的朋友(比如A和B是朋友,A和C也是朋友,那么A,B,C他们三个就互为朋友。)
而由于我们给数据时只会给K个数,代表这K个人是朋友(一般K的值是2)

并查集作用

1.用来看某个人A和另一个人B是不是朋友,
2.用于查看n个人中,组成了几个朋友圈(两个朋友圈就代表,这两组人互不认识)。
3.有时候求N个城市还需要修几条路才能完完全畅通
4. … …

举实例说明

杭电oj1232:畅通工程

Problem Description
某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?

Input
测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。
注意:两个城市之间可以有多条道路相通,也就是说
3 3
1 2
1 2
2 1
这种输入也是合法的
当N为0时,输入结束,该用例不被处理。

Output
对每个测试用例,在1行里输出最少还需要建设的道路数目。

Sample Input
4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0

Sample Output
1
0
2
998

思路

首先,这道题符合并查集作用3。
想要知道还需要建几条路,我们只需要知道现在有几个“朋友圈”即可,比如现在有n个“朋友圈”。那么我们只需要再修建(n-1)条路就可以了。

===========================================================================================================

并查集代码

我们拆分一下:
第一部分:求祖先
我们为每一个人设置一个“祖先”per[i]。
也就是说我们在一个朋友圈选一个祖先A,只要和A是直接或者间接是朋友的我们都把他的祖先定为A,也就是说per[i]=A,per[j]=A。

int father(int a) //寻找祖先,利用递归
{
    if(per[a]==a)
        return a;
    else
    {
        per[a]=father(per[a]);
        return per[a];
    }
}

第二部分:查看是否属有相同祖先
现在新输入2个人,他们两个有关系。我们就要看看他本来在不在一个圈子里。不在的话就和成一个圈子
如果i和j的祖先相同,即per[i]==per[j]那么i和j就在一个朋友圈。如果他们不在一个朋友圈,可是现在他们两个成朋友了所以需要合成一个朋友圈

void join(int x,int y) //合并朋友圈
{
    int root1,root2;
    root1=father(x);
    root2=father(y);
    if(root1!=root2)
        per[root1]=root2;
}

那么我们来解决一下这道题

#include<bits/stdc++.h>

using namespace std;
int per[1010];
void sta(int n)      //初始化
{
    for(int i=1;i<=n;i++)
        per[i]=i;
}

int father(int a)   //找祖先
{
    if(per[a]==a)
        return a;
    else
    {
        per[a]=father(per[a]);
        return per[a];
    }
}

void join(int x,int y)   //合并朋友圈
{
    int root1,root2;
    root1=father(x);
    root2=father(y);
    if(root1!=root2)
        per[root1]=root2;
}

int main() 
{
	int m,n,a,b;
	while(scanf("%d",&n)&&n)
    {
        sta(n);
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d %d",&a,&b);
            join(a,b);
        }
        int sum=0;
        for(int i=1;i<=n;i++) //祖先是自己一定代表有一个朋友圈
        {
            if(per[i]==i)
                sum++;
        }
        printf("%d\n",sum-1);
    }
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章