具體實現用樹形結構,若是a,b所在組相同,則a,b有相同的根結點。合併兩組時即讓一組的根向另外一組相連。網絡
爲了不樹形結構下發生退化的狀況,在並查集中能夠以下操做:數據結構
此外還能夠路徑壓縮,即把每一個結點都直接與其根結點相連,樹的高度爲2.在查詢過程當中查詢過程當中遞歸的全部節點都直接指向根結點。spa
此時爲方便起見,即便樹的高度改變,咱們也不修改rank的值(rank只是在合併時決定誰向誰連根)。code
具體見下實現代碼。blog
若(u,v)之間有邊,則將u,v放入同一組。若是在放入u,v以前已經在同一組,即從u能夠到v,那麼加入邊(u,v)後就造成了一個環。遞歸
以u或v做爲環的起點,用dfs方法遍歷每一個頂點相鄰的頂點,看最後是否回到了起點,若是沿某一路徑回到起點,則說明這些it
頂點在這個環內。io
#include<cstdio> #include<algorithm> #include<vector> using namespace std; const int Max_N = 100000; //輸入 int n; int s;//環的起點 vector<int> G[Max_N+1];//圖 vector<int> V;//記錄環 bool visited[Max_N+1];//結點是否訪問過(避免重複訪問) int par[Max_N+1];//並查集 int rank[Max_N+1];//並查集高度 //初始化並查集 void init(int n) { for(int i=1; i<=n; i++){//剛開始互相沒有邊相連 par[i] = i; } } //找下標x的根 int find(int x) { return x==par[x] ? x:par[x] = find(par[x]);//par[x] = find(par[x])即路徑壓縮 } //合併 void unite(int x,int y) { x = find(x); y=find(y);//先找到他們的根 if( x==y ){ return;//同根 直接返回 } if( rank[x]<rank[y] ){ par[x] = y;//將x所在的樹合併在y下 } else { par[y] = x; if( rank[x]==rank[y] ){//若是高度相同 更新rank[x] rank[x]++; } } } //x,y是否在同一組 便是否同根 bool same(int x,int y) { return find(x)==find(y); } //dfs bool dfs(int u) { if( visited[u] )//若是最後訪問的結點回到起點,則在環內 { if( u==s ) { return true; } return false;//不然不在環內 } visited[u] = true;//u已經訪問過 for(int i=0; i<G[u].size(); i++)//遍歷頂點 u 的相鄰邊 { int v = G[u][i];//下一個頂點 if( dfs(v) )//在環內 { V.push_back(v); return true; } } return false;//遍歷全部邊都不在環內 } void solve() { dfs(s); sort(V.begin(),V.end()); vector<int>::iterator it; for( it=V.begin(); it!=V.end(); it++) { printf("%d ",*it); } printf("\n"); } int main() { scanf("%d",&n); init(n); while( n-- ) { int u,v; scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); if( same(u,v) ){//u,v已經有路徑了 s = u;//起點下標 } unite(u,v); } solve(); return 0; }