详解并查集

时间:2024-01-25 18:45:43

详解并查集

                                                                                                              详解并查集

                                       Powered by WSY in SSF

                               2019-11-02  13:46

【1】并查集的定义:

  并查集(Disjoint  Set)是一种非常精巧的非常实用的数据结构,它主要用来处理一些不相交集合的合并问题,经典的例子有联通子图,最小生成树的克鲁斯-卡尔算法。


 

【2】并查集的经典问题:

  我们通常使用“帮派”、“团伙”等问题举例说明并查集。例如帮派问题:

  在某城市里住着n个人,任何两个认识的人不是朋友就是敌人,而且满足: 1、 我朋友的朋友是我的朋友; 2、 我敌人的敌人是我的朋友; 所有是朋友的人组成一个团伙。告诉你关于这n个人的m条信息,即某两个人是朋友,或者某两个人是敌人,请你编写一个程序,计算出这个城市最多可能有多少个团伙?

   这是一个非常经典的并查集问题,接下来就用这个问题的代码为您详解并查集。


 

【3】并查集问题的基本思路:

  第一步   初始化:

  我们需要对存储公共祖先的数组进行初始化,一般情况下,将该数组命名为S。

  首先,我们说 s[i] 是以节点 为元素的独立集合,在开始的时候不处理他和它的朋友之间的关系。

  然后,以元素 i 的值表示他的集 s[i] 的值,例如 元素1的集 s[1]=1,如图1.1所示。

  

  第二步   计算+合并:

  合并,例如加入第1个朋友关系(1,2),如图1.2所示,在并查集S中,把节点1合并到节点2。

  

  之后,以此类推,直到合并成如图1.3的样子。

  

  


 

  代码君:

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int MAXN=1000+50;
 4 int R[MAXN],enemry[MAXN];
 5 int Find(int x)
 6 {
 7     return (!R[x])?x:(Find(R[x]));
 8 }
 9 void Union(int a, int b) 
10 {
11     a=Find(a); 
12     b=Find(b);
13     if(a==b) return;  
14     if(a!=b) R[b]=a;
15 }
16 int main()
17 {
18     memset(R,0,sizeof(R));
19     memset(enemry,0,sizeof(enemry));
20     int m,n,x,y,j;
21     int ans=0;
22     char ch;
23     cin>>n>>m;
24     for(int i=0;i<m;i++)
25     {
26         cin>>ch>>x>>y;
27         if(ch=='0')
28         {
29             if(enemry[x]) Union(y,enemry[x]);
30             else enemry[x]=y;
31             if(enemry[y]) Union(x,enemry[y]);
32             else enemry[y]=x;
33         }
34         else Union(x,y);
35     }
36     for(int i=1;i<=n;i++)
37     {   
38         j=Find(i);
39         if(j==i) ans++;
40     }
41     cout<<ans<<endl;
42     return 0;
43 }//代码来源:https://blog.csdn.net/hyqsblog/article/details/45057877
复制代码

 


 

【4】代码解读+详解

  再次感谢  https://blog.csdn.net/hyqsblog/article/details/45057877  提供的代码。

  从主函数开始。

  第18-19行,第1部分,初始化

  初始化R数组,enemry数组(这里很重要,在某些涉及到多组数据的题目时,初始化如果不写,会酿成大错)

  第20-23行,第2部分,基础定义+输入

  这里定义了一些基本的,后面需要使用的变量。

  之后还有一些基础的输入,包括N和M。

  第24-35行,第3部分,循环查找,实现并查集中的 “合并”

  循环,循环每组关系,查找。

  Line 27:如果这组关系是 “敌对”,那么就使用Union函数实现 “敌对合并” 的操作

  Line 34:如果这组关系是 “友好”,那么就使用Union函数实现 “友好合并” 的操作

  第9-15行,第4部分,实现合并

  使用Find函数实现查找合并

  第5-8行,第5部分,实现查找

  全文只有一句话,但是能实现具体的返回判断,使用二次元运算符