HDU 1213 How Many Tables(并查集)
http://acm.hdu.edu.cn/showproblem.php?pid=1213
题意:
现在给你由1到N个数字组成的M对整数对,问你有多少个连通分量。每对整数X和Y(X不等于Y)表示X和Y在一个连通分量里面。
输入:首先是T(1<=T<=25),表示实例个数。然后每个实例第一行为N和M(1<=N,M<=1000),表示整数从1到N,接下来有M对整数。
输出:连通分量个数。
分析:
直接读取数据,合并每一对数字节点所属的连通分量即可。最后算一共有多少个连通分量有两种方法:
1.可以求出一共有多少个根节点(即fa[i]==-1的i个数)
2.可以用原始连通分量数n 减去 有效的合并次数。即每次合并两个连通分量就会使得总的分量数目减少1.
AC代码(新):
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1000+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 T;
scanf("%d",&T);
while(T--)
{
memset(fa,-1,sizeof(fa));
int n,m;
scanf("%d%d",&n,&m);
int cnt=n;//初始连通分量数
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
cnt -= bind(u,v);
}
printf("%d\n",cnt);
}
return 0;
}
AC代码:方法1计算的
#include<cstdio>
#include<cstring>
#include<set>
using namespace std;
const int MAXN = 1100;
int pa[MAXN];
int findset(int x)
{
if(pa[x]==-1)return x;
return pa[x]=findset(pa[x]);
}
void bind(int i,int j)//尝试合并i和j的连通分量
{
int fa = findset(i);
int fb = findset(j);
if(fa!=fb)
pa[fa]=fb;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
pa[i]=-1;
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
bind(x,y);
}
int ans=0;
for(int i=1;i<=n;i++)
if(pa[i]==-1)ans++;
printf("%d\n",ans);
}
return 0;
}
new AC code:方法2计算的
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1000+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 T; scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) fa[i]=-1;
int ans=n;//最终连通分量数
while(m--)
{
int u,v;
scanf("%d%d",&u,&v);
ans-=bind(u,v);
}
printf("%d\n",ans);
}
return 0;
}