并查集小结
并查集是一种竞赛中常用的数据结构,在解决划分集合问题,帮派问题,朋友关系问题方面有着很广的应用;
而对于并查集来说,基本的操作可以分为合并集合,查找集合,初始化集合等基本操作;
而对于并查集的应用背景,是这样的:一个城市有n个人,给出这些人的关系,比如1号,2号是朋友,2,3号也是朋友,那么1,3号就是朋友关系,在分析这些朋友的关系之后,我们就可以将这些是朋友的人划分为同一集合,最后统计有多少帮派
对于并查集的基本概念我觉得有必要总结一下:将1~n的不同对象划分为若干个不相交的集合,在每个集合中,选择某个元素代表所在的集合。
对于初始化我觉得有必要说一下:
我们初始化每个集合为以节点为元素的并查集,那么在开始的时候,每个集合都是独立的;
其余的有一篇讲的很好的博客,以喜闻乐见的火影来讲的,很有趣味性和可读性:
https://blog.csdn.net/weixin_38279101/article/details/112546053(转载)
实战项目:https://www.luogu.com.cn/problem/P1551
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int num=5010; 4 int s[num];//集合 5 int height[num];//树的高度 6 int n,m,p; 7 void init_set()//初始化集合 8 { 9 for(register int i=1;i<=n;i++) 10 { 11 s[i]=i; 12 height[i]=0; 13 } 14 } 15 int find_set(int x)//查找函数 16 { 17 if(x!=s[x]) 18 s[x]=find_set(s[x]); 19 return s[x]; 20 } 21 void union_set(int x,int y)//合并函数 22 { 23 x=find_set(x); 24 y=find_set(y); 25 if(height[x]==height[y]) 26 { 27 height[x]=height[x]+1; 28 s[y]=x; 29 } 30 if(height[x]<height[y]) 31 { 32 s[x]=y; 33 } 34 else 35 s[y]=x; 36 } 37 int main() 38 { 39 std::ios::sync_with_stdio(false); 40 cin>>n>>m>>p; 41 init_set(); 42 for(register int i=1;i<=m;i++) 43 { 44 int x,y; 45 cin>>x>>y; 46 union_set(x,y); 47 } 48 for(register int i=1;i<=p;i++) 49 { 50 int a,b; 51 cin>>a>>b; 52 if(find_set(a)==find_set(b))//如果是同一集合 53 printf("Yes\n"); 54 else 55 printf("No\n"); 56 } 57 return 0; 58 }
https://www.luogu.com.cn/problem/P1536
1 #include<bits/stdc++.h> 2 using namespace std; 3 int s[1010];//集合 4 int height[1010];//树的高度 5 int ans;//统计 6 int n,m; 7 void init_set()//合并 8 { 9 for(register int i=1;i<=n;i++) 10 { 11 s[i]=i; 12 height[i]=0; 13 } 14 } 15 int find_set(int x)//查找 -路压 16 { 17 if(x!=s[x]) 18 { 19 s[x]=find_set(s[x]); 20 } 21 return s[x]; 22 } 23 void union_set(int x,int y)//合并优化 24 { 25 x=find_set(x); 26 y=find_set(y); 27 if(height[x]==height[y]) 28 { 29 height[x]=height[x]+1; 30 s[y]=x; 31 } 32 if(height[x]<height[y]) 33 { 34 s[x]=y; 35 } 36 else 37 { 38 s[y]=x; 39 } 40 } 41 int main() 42 { 43 std::ios::sync_with_stdio(false); 44 while(cin>>n>>m) 45 { 46 if(n==0) 47 return 0; 48 ans=0; 49 init_set(); 50 for(register int i=1;i<=m;i++) 51 { 52 int x,y; 53 cin>>x>>y; 54 int a=find_set(x); 55 int b=find_set(y); 56 if(a!=b) 57 union_set(a,b); 58 } 59 for(register int j=1;j<=n;j++) 60 { 61 if(find_set(j)==j) 62 { 63 ans++; 64 } 65 } 66 cout<<ans-1<<endl; 67 } 68 return 0; 69 }
还有我的一篇博客:https://www.cnblogs.com/LQS-blog/p/16179533.html,
也是很经典的并查集问题
本文来自博客园,作者:江上舟摇,转载请注明原文链接:https://www.cnblogs.com/LQS-blog/p/16190771.html