简单并查集 -- HDU 1232 UVALA 3644 HDU 1856
并查集模板:
1 #include<iostream> 2 using namespace std; 3 int Rank[1001],x,y; 4 int v[1001]; 5 //初始化 x 集合 6 void init(int n) 7 { 8 for(int i=0; i<n; i++) 9 { 10 v[i]=i; 11 Rank[i]=0; 12 } 13 } 14 //查找 x 所在的集合 15 int find_set(int x) 16 { 17 if(v[x]!=x) v[x]=find_set(v[x]); 18 return v[x]; 19 } 20 ///更新根节点,有可能会暴栈 21 int mix(int x,int y) 22 { 23 int fx,fy; 24 fx=find_set(x); 25 fy=find_set(y); 26 if(fx!=fy) 27 p[fx]=fy; 28 } 29 //合并 x, y 所在的集合,用到路径压缩,按秩合并 30 void Union(int x,int y) 31 { 32 x=find_set(x); 33 y=find_set(y); 34 if(Rank[x]>Rank[y]) 35 v[y]=x; 36 else if(Rank[x]<Rank[y]) 37 v[x]=y; 38 else if(Rank[x]==Rank[y]) 39 { 40 v[x]=y; 41 Rank[y]++; 42 } 43 } 44 int main() 45 { 46 return 0; 47 }
计算环的个数,需要缩点:
1 #include <iostream> 2 #include <cmath> 3 #include <cstdio> 4 #include <cstring> 5 #include <cstdlib> 6 #include <string> 7 #include <sstream> 8 #include <algorithm> 9 #define maxn 100010 10 #define INF 0x7fffffff 11 #include <queue> 12 #define N 1000010 13 #define ll __int64 14 #define mem(a,b) memset(a,b,sizeof(a)) 15 #define repu(i, a, b) for(int i = (a); i < (b); i++) 16 const double PI=-acos(-1.0); 17 using namesPce std; 18 ///初始化 x 集合 19 int P[maxn],Rank[maxn]; 20 void mix() 21 { 22 repu(i,0,maxn) 23 { 24 P[i]=i; 25 Rank[i]=0; 26 } 27 } 28 ///查找 x 所在的集合 29 int find_set(int x) 30 { 31 if(P[x]!=x) 32 P[x]=find_set(P[x]); 33 return P[x]; 34 } 35 ///缩点,合并 x, y 所在的集合,用到路径压缩,按秩合并 36 void Union(int x,int y) 37 { 38 x=find_set(x); 39 y=find_set(y); 40 if(Rank[x]>Rank[y]) 41 P[y]=x; 42 else if(Rank[x]<Rank[y]) 43 P[x]=y; 44 else if(Rank[x]==Rank[y]) 45 { 46 P[x]=y; 47 Rank[y]++; 48 } 49 } 50 int main() 51 { 52 int x,y; 53 while(scanf("%d",&x) == 1) 54 { 55 mix(); 56 int refu = 0; 57 while(x!=-1) 58 { 59 scanf("%d",&y); 60 x = find_set(x); 61 y = find_set(y); 62 if(x == y)///如果同一个根节点,就是环 63 ++refu; 64 else 65 Union(x,y); 66 scanf("%d",&x); 67 } 68 printf("%d\n",refu); 69 } 70 return 0; 71 }
计算联通块的个数
题意:n个结点,m条边,求再连几条边能使得全部结点连通;
思路:并查集,求该图中有几个连通分支,然后连通块的个数-1;
1 #include<iostream> 2 #include<string> 3 #include<cstdio> 4 #include<cstring> 5 #include<cstdlib> 6 #include<algorithm> 7 #include<cmath> 8 using namespace std; 9 int p[50001]; 10 int n,m; 11 int a,b; 12 int find_set(int x) 13 { 14 return p[x]==x?x:find_set(p[x]); 15 } 16 void mix(int x,int y) 17 { 18 int fx,fy; 19 fx=find_set(x); 20 fy=find_set(y); 21 if(fx!=fy) 22 p[fx]=fy; 23 } 24 int main() 25 { 26 int cas=1; 27 while(scanf("%d",&n)&&n) 28 { 29 scanf("%d",&m); 30 int count=0; 31 for(int i=1; i<=n; i++) 32 p[i]=i; 33 for(int j=1; j<=m; j++) 34 { 35 scanf("%d%d",&a,&b); 36 mix(a,b); 37 } 38 for(int i=1; i<=n; i++) 39 if(p[i]==i) count++; 40 printf("%d\n",count-1); 41 } 42 return 0; 43 }
计算每个连通块个数,取最大:
1 #include<cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <algorithm> 5 using namespace std; 6 struct A 7 { 8 int num,pre; 9 } Set[10000011]; 10 void init(int n)///初始化 11 { 12 int i; 13 for(i=1; i<=n; i++) 14 { 15 Set[i].num=1; 16 Set[i].pre=i; 17 } 18 } 19 int Find(int k)///找根节点 20 { 21 if(Set[k].pre==k) 22 return k; 23 return Set[k].pre = Find(Set[k].pre); 24 } 25 int main() 26 { 27 int n,maxn,ans,i,f1,f2; 28 int x[100011],y[100011]; 29 while(~scanf("%d",&n)) 30 { 31 if(n==0) 32 { 33 printf("1\n"); 34 continue; 35 } 36 maxn=0; 37 for(i=1; i<=n; i++) 38 { 39 scanf("%d%d",&x[i],&y[i]); 40 maxn = max(maxn,max(x[i],y[i])); 41 } 42 init(maxn); 43 for(i=1; i<=n; i++) 44 { 45 f1=Find(x[i]); 46 f2=Find(y[i]); 47 if(f1!=f2) 48 { 49 Set[f1].pre=f2; 50 Set[f2].num += Set[f1].num;///把该节点的子节点加上 51 } 52 } 53 ans=0; 54 for(i=1; i<=maxn; i++) 55 ans=max(ans,Set[i].num); 56 printf("%d\n",ans); 57 } 58 return 0; 59 }
人生就像心电图,想要一帆风顺,除非game-over