POJ 2524 Ubiquitous Religions(并查集)
http://poj.org/problem?id=2524
题意:
给你n个节点(节点编号1到n)和m条边,然后问你无向图有多少个连通分量.
分析:
初始连通分量有n个。每读入一条边,如果这条边的两个点不在一个连通分量,那么合并两点所属的连通分量。总的连通分量数目就减少1。
输出最终剩余连通分量数目即可。
AC代码(新):297ms
#include<cstdio> #include<cstring> using namespace std; const int maxn=50000+5; int fa[maxn]; int findset(int x) { return fa[x]==-1? x: fa[x]=findset(fa[x]); } int bind(int u,int v) { int fu=findset(u); int fv=findset(v); if(fu!=fv) { fa[fu]=fv; return 1; } return 0; } int main() { int n,m; int kase=0; while(scanf("%d%d",&n,&m)==2 && n) { memset(fa,-1,sizeof(fa)); int cnt = n;//剩余连通分量数目 while(m--) { int u,v; scanf("%d%d",&u,&v); cnt -= bind(u,v); } printf("Case %d: %d\n",++kase,cnt); } return 0; }
AC代码:344ms
#include<cstdio> #include<cstring> using namespace std; const int MAXN=50000+100; int F[MAXN]; int findset(int i) { if(F[i]==-1)return i; return F[i]=findset(F[i]); } void bind(int i,int j) { int fa=findset(i); int fb=findset(j); if(fa!=fb) { F[fb]=fa; } } int main() { int n,m,kase=1; while(scanf("%d%d",&n,&m)==2) { if(n==0&&m==0)break; int ans=n; memset(F,-1,sizeof(F)); while(m--) { int a,b; scanf("%d%d",&a,&b); int fa=findset(a); int fb=findset(b); if(fa!=fb) { ans--; bind(a,b); } } printf("Case %d: %d\n",kase++,ans); } return 0; }