算法思想:
1.初始化功能:把每个点所在集合初始化为其自身。
2.查找功能:查找元素所在的集合,即根节点。
2.合并功能:将两个元素所在的集合合并为一个集合。
例题:若某个家族人员过于庞大,要判断两个是否是亲戚,确实不容易,给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。
1 //初始化 2 for(int i=0;i<n;i++) 3 { 4 SUB-Make-Set(i); 5 } 6 //合并 7 for(int i=0;i<n;i++) 8 { 9 if(SUB-Find-Set(ai) != SUB-Find-Set(bi)) 10 { 11 SUB-Union(ai, bi); 12 } 13 } 14 15 //询问 16 fou(int i=0;i<n;i++) 17 { 18 if(SUB-Find-Set(ci)==SUB-Find-Set(di)) 19 { 20 output “Yes” 21 } 22 else 23 { 24 output “No” 25 } 26 }
1 SUB-Make-Set(x) 2 { 3 for(int i=0;i<x;i++) 4 { 5 head[x]=x; 6 tail[x]=x; 7 next[x]=0; 8 } 9 }
1 SUB-Find-Set(x) 2 { 3 return head[x]; 4 }
1 SUB-Union(a,b) 2 { 3 next[tail[head[a]]]=head[b]; 4 int p=head[b]; 5 while(p!=0) 6 { 7 head[p]=head[a]; 8 p=next[p]; 9 } 10 }
1 SUB-Make-Set(x) 2 { 3 for(int i=0;i<x;i++) 4 { 5 p[i]=i; 6 rank[i]=0; 7 } 8 }
1 SUB-Union(a,b) 2 { 3 //SUB-Link(SUB-Find-Set(a),SUB-Find-Set(b)) 4 SUB-Link(a,b) 5 p[a]=b; 6 }
1 SUB-Find-Set(x) 2 { 3 if(x==p[a]) 4 { 5 return x; 6 } 7 else 8 { 9 return SUB-Find-Set(p[x]); 10 } 11 }
1 SUB-Link(a,b) 2 { 3 if(rank[a]>rank[b]) 4 { 5 p[b]=a; 6 rank[b]+=rank[a]; 7 } 8 else 9 { 10 p[a]=b; 11 rank[a]+=rank[b]; 12 } 13 }
1 SUB-Find-Set(x) 2 { 3 if(x!=p[x]) 4 { 5 p[x]=SUB-Find-Set(p[x]); 6 } 7 return p[x]; 8 }
1 SUB-Find-Set(x) 2 { 3 int r=x; 4 while(r!=p[x]) 5 { 6 r=p[r]; 7 } 8 while x?r 9 do q←p[x] 10 p[x]←r 11 x←q 12 return r 13 }
1 int find(int x) 2 { 3 if(fa[x]==x) 4 { 5 return x; 6 } 7 return fa[x]=find(fa[x]); 8 }
模板:
1 /fa[x]表示x的最远祖先 2 int fa[50002]; 3 //初始化,一开始每个点单独成集合 4 void build(int qwq) 5 { 6 for(int i=1;i<=qwq;i++) 7 { 8 fa[i]=i; 9 } 10 return ; 11 } 12 //找到x的最远祖先,并且压缩路径 13 int find(int x) 14 { 15 if(fa[x]==x) 16 { 17 return x; 18 } 19 return fa[x]=find(fa[x]); 20 } 21 //判断x,y是不是在同一个集合里,直接判断最远祖先是不是一样的 22 bool che(int x,int y) 23 { 24 return find(x)==find(y); 25 } 26 //合并x,y,我们在判断x和y是不是同一个集合里, 27 //路径压缩之后fa[x],fa[y]已经是最远祖先了, 28 //所以直接将fa[x]的父亲连接在fa[y]的祖先上 29 void mer(int x,int y) 30 { 31 if(!che(x,y)) 32 { 33 fa[fa[x]]=fa[y]; 34 } 35 return ; 36 }
原文:https://www.cnblogs.com/mzchuan/p/11586789.html