题解 | #畅通工程#
畅通工程
http://www.nowcoder.com/practice/4878e6c6a24e443aac5211d194cf3913
一、解题流程:
1. 循环输入城镇和道路数
2. 初始化:
- 初始化2个数组 father,height(Initial函数)
- 将所有城镇看为一个独立的个体,此时爸爸是自己,高度为0
3. 输入相连的城镇:
- (1)查找城镇所在集合即“查找集合根节点”(Find函数)
- (2)不在同一集合进行合并(Union函数)
4.计算需要的道路数:
- (1)初始化answer为-1
- (2)如果全部连通,则集合个数为1,只有根节点的父亲为自己,answer++为0,不需要添加道路
- (3)如果是两个集合,说明还需要一条路连接这两个集合。有两个根节点的父亲为自己,answer++操作两次,answer=1。以此类推
二、代码如下(C++):
#include<iostream>
using namespace std;
const int MAXN=1000+10;
int father[MAXN];
int height[MAXN];
//初始化,每个城镇是一个独立的个体,爸爸是自己,高度为0
void Initial(int n)
{
for(int i=1;i<=n;i++)
{
father[i]=i;
height[i]=0;
}
return ;
}
//找根节点,不断的Find(father【i】)
int Find(int x)
{
if(x!=father[x])
father[x]=Find(father[x]); //路径压缩
return father[x];
}
//合并
void Union(int x,int y)
{
x=Find(x); // 找到x的根节点
y=Find(y); // 找到y的根节点
if(x!=y) // 两个不是一个集合
{
if(height[x]<height[y])
father[x]=y;
else if(height[x]>height[y])
father[y]=x;
else
{
father[x]=y;
height[y]++;
}
}
return ;
}
int main()
{
int n,m; // n城镇 m道路
while(cin>>n>>m) // 循环输入
{
if(n==0) // 输入停止的判断
break;
Initial(n); // 初始化所有道路
while(m--)
{
int x,y;
scanf("%d",&x);
scanf("%d",&y);
Union(x, y); // 将城镇合并
}
int answer=-1; // 记录还需要的道路数
for(int i=1;i<=n;i++) // 循环遍历所有节点,看他们的根节点是否是自己
{
if(Find(i)==i)
answer++;
}
printf("%d\n",answer);
}
return 0;
}