这篇博客讲的很nice 原地址
hdu1232
题意大概是有N个城市 城市之间有M条马路使他们两两相连 然后求还要加多少条路可以让所有的城市相通 这里的相通不一定是说两个城市之间直接相同 也可以路过其他的城市
先上代码 上面那篇博客讲的很清楚 例题也是这一题
#include<bits/stdc++.h> typedef long long ll; using namespace std; int fa[1050]; bool t[1050]; ll find(ll x){ return x==fa[x] ? x : (fa[x]=find(fa[x])); } void merge(ll a,ll b){ int fx=find(a),fy=find(b); if(fx!=fy) fa[fy]=fx; } void inti(int n){ for(ll i=1;i<=n;++i) fa[i]=i; } int main(void){ ios::sync_with_stdio(false); ll N,M; while(cin>>N&&N){ cin>>M; ll a,b; inti(i) for(ll i=1;i<=M;++i){ cin>>a>>b; merge(a,b); } memset(t,0,sizeof(t)); for(ll i=1;i<=N;++i) //这一步就相当于标记每一个的父节点 最后只要统计父节点就可以了 t[find(i)]=1; ll ans=0; for(ll i=1;i<=N;++i){ if(t[i]) ans++; } cout<<ans-1<<endl; } return 0; }
下面是按秩合并 原文地址
按秩合并的优势在于将简单的往复杂的上面合并 这样就可以有效地减低树的复杂度
按秩合并的改变加入了一个rank数组 用来记录每一个点的深度 这样就可以在合并时比较深度进行合并
初始化
inline void init(int n) { for (int i = 1; i <= n; ++i) { fa[i] = i; rank[i] = 1; } }
然后是合并时
inline void merge(int i, int j) { int x = find(i), y = find(j); //先找到两个根节点 if (rank[x] <= rank[y]) fa[x] = y; else fa[y] = x; if (rank[x] == rank[y] && x!=y) rank[y]++; //如果深度相同且根节点不同,则新的根节点的深度+1 }