题目链接:hdu1232畅通工程
这一题是并查集的题,关键就是找出根结点的数目,下面附上详细的代码和注释讲解:
(注释中 祖先=根节点)
#include<bits/stdc++.h>
int m,n,pre[1010],rank[1010];//pre数组存关系(pre[a]==b表示a的父亲是b),rank数组存树上有多少节点(rank[i]==j表示根节点为i的树上有j个节点)
void unit(int a)//初始化函数
{
for(int i=1;i<=a;i++)
pre[i]=i,rank[i]=1;
}
int find(int x)//找祖先函数,find(a)的返回值即是a的祖先
{
int t=x;//把x存在t中
while(x!=pre[x]) x=pre[x];//通过不断的找父亲操作,最终找到x的祖先
if(t!=x)//这个if循环是个优化 ,避免树太长,查找超时。
{
int r=pre[t];//暂存t的父亲
pre[t]=x;
t=r;
}
return x;
}
int un(int a,int b)//连接a,b到一棵树上
{
a=find(a);
b=find(b);
if(a==b)//a,b的祖先一样,那么就不需要连接了
return 0;
if(rank[a]>=rank[b])//a比b长,把b接到a树上
{
pre[b]=a;
rank[a]+=rank[b];
}
else//b比a长,把a接到b树上
{
pre[a]=b;
rank[b]+=rank[a];
}
}
int main()
{
int i,j,a,b,c;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0)
break;
unit(n); //对n个城镇初始化
for(i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
un(a,b);
}
int num=0;
for(i=1;i<=n;i++)//用一个for循环得到祖先的数目
if(pre[i]==i)
num++;
printf("%d\n",num-1);//祖先数目-1就是需要修的路的数量
}
}