並查集分析與擴展
阿新 • • 發佈:2018-02-12
acm pan 父親 數據 scan namespace con building stream 即生成若幹個超級父親,每個節點的父親都是一個超級父親;
刪除就直接令自己的父親等於自己;
http://jarily.com/acm/2012/11/26/bcj.html
一 並查集的基礎
1 基本功能
並查集用於處理不相交數據集合;
2 基本操作
(1)查找一個元素的祖先(即查找這個元素屬於哪個集合);
(2)將兩個元素所在的集合合並為一個集合;
(3)刪除操作,即把某個元素從它所在的集合中刪除;
3 基本代碼
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int N=30030; int n; int f[N],rank[N],num[N];void init()//初始化 { for(int i=1; i<=n; i++) f[i]=i; } int getFather(int x)//查找元素x的祖先 { if(f[x]==x) return f[x]; f[x]=getFather(f[x]);//路徑壓縮 return f[x]; } void unionSet(int x,int y)//將兩個元素所在的集合合並為一個集合 { int xx=getFather(x),yy=getFather(y); if(xx!=yy) f[xx]=yy; }
二 並查集的擴展
1 記錄每個集合的元素個數
在此初始化以及合並集合的時候處理一下集合的元素個數即可;
代碼
void _init() { int i; for(i=1; i<=n; i++) f[i]=i,num[i]=1; } void _unionSet(int x,int y) { int xx=getFather(x),yy=getFather(y); if(xx!=yy) f[xx]=yy,num[yy]+=num[xx]; }
2 並查集的刪除
即把某個元素從它所在的集合中刪除;
刪除就直接令自己的父親等於自己;
代碼
int s; void __init() { for(int i=1; i<=n; i++) f[i]=i; s=n+1; } int __getFather(int x) { if(f[x]==x) return f[x]; f[x]=getFather(f[x]); return f[x]; } void __unionSet(int x,int y) { int xx=getFather(x),yy=getFather(y); if(xx!=yy) { if(xx>n) f[yy]=xx; else if(yy>n) f[xx]=yy; else f[xx]=s,f[yy]=s,f[s]=s,s++; } } void deleteX(int x) { f[x]=x; }
3 rank數組的應用;
其基本定義是一個元素到它的祖先的路徑長度;
三 算法應用-HDU2818;
1 題目鏈接
Building Block
2 題目大意
有n個箱子,然後是兩種操作:
(1)把x所在的那一摞箱子搬到y所在的那一摞上面;
(2)詢問x的下面有幾個箱子;
3 代碼
int getF(int x) { if(f[x]==x) return x; int t=f[x];//做完getFather之後再更新rank f[x]=getF(f[x]),rank[x]+=rank[t];//rank[x]代表x到它的祖先的距離,即x的上面還有幾個箱子 return f[x]; } int main() { //freopen("C:\\Users\\Administrator\\Desktop\\kd.txt","r",stdin); char te[5]; while(~scanf("%d",&n)) { for(int i=0; i<=30000; i++) f[i]=i,num[i]=1,rank[i]=0; for(int i=0; i<n; i++) { int x,y; scanf("%s",te); if(te[0]==‘M‘) { scanf("%d%d",&x,&y); int xx=getF(x); int yy=getF(y); if(xx!=yy) f[yy]=xx,rank[yy]=num[xx],num[xx]+=num[yy]; } else { scanf("%d",&x); printf("%d\n",num[getF(x)]-rank[x]-1); } } } return 0; }
並查集分析與擴展