并查集:就是有求并集,查找元素属于哪个集合的功能。
1、路径压缩:使X到根上的每一个节点的父节点都变为根节点。
查询:
void Find(int x) { if(a[x]==0) return x; else return a[x]=Find(a[x]); }
合并:
void Merge(int x,int y) { int t1=Find(x),t2=Find(y); if(t1!=t2) a[t1]=t2; }
2、按秩合并:使较浅的树成为较深的树的子树。
查询:
void Find(int x) { if(a[x]==0) return x; else return a[x]=Find(a[x]); }
合并:
void Merge(int x,int y) { int t1=Find(x),t2=Find(y); if(t1!=t2){ if(rank[t1]<=rank[t2]) a[t1]=t2,rank[t2]=max(rank[t2],rank[t1]+1); else a[t2]=t1,rank[t1]=max(rank[t1],rank[t2]+1); } }
例题:hdu1232
解法一:路径压缩
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 1200; int fa[maxn]; int f(int x) { if(fa[x]==0) return x; else return fa[x]=f(fa[x]); } int main(void) { int n,m,t1,t2,i,x,y; while(~scanf("%d",&n)&&n){ scanf("%d",&m); memset(fa,0,sizeof(fa)); while(m--){ scanf("%d%d",&x,&y); t1=f(x),t2=f(y); if(t1!=t2) fa[t1]=t2; } int cnt=0; for(i=1;i<=n;i++){ if(fa[i]==0) cnt++; } printf("%d ",cnt-1); } return 0; }
解法二:按秩求和
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 1200; int fa[maxn],rk[maxn]; int f(int x){ if(fa[x]==0) return x; else return fa[x]=f(fa[x]); } int MAX(int x,int y) { return x>y?x:y; } int main(void) { int n,m,x,y,t1,t2,i; while(~scanf("%d",&n)&&n){ scanf("%d",&m); memset(fa,0,sizeof(fa)); memset(rk,0,sizeof(rk)); while(m--){ scanf("%d%d",&x,&y); t1=f(x),t2=f(y); if(t1!=t2){ if(rk[t1]<=rk[t2]) fa[t1]=t2,rk[t1]=MAX(rk[t1],rk[t2]+1); else fa[t2]=t1,rk[t2]=MAX(rk[t2],rk[t1]+1); } } int cnt=0; for(i=1;i<=n;i++) if(fa[i]==0) cnt++; printf("%d ",cnt-1); } return 0; }