Description
某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?
Input
测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。
注意:两个城市之间可以有多条道路相通,也就是说
3 3
1 2
1 2
2 1
这种输入也是合法的
当N为0时,输入结束,该用例不被处理。
Output
对每个测试用例,在1行里输出最少还需要建设的道路数目。
Sample Input
4 2 1 3 4 3 3 3 1 2 1 3 2 3 5 2 1 2 3 5 999 0 0
Sample Output
1
0
2
998
并查集,说起来惭愧啊。。。。之前一直在学,每次明白了马上放下了。。。。就再也不看了。。。。然后就忘了。。。于是我决定在这个深夜,整理出来。嗯!
说到并查集,那么字面意思拆分开就是:并,查。其实是用两个函数实现的,两个函数其实并不是很难理解。
下面我们来看一下查的代码:
int pre[1007];
int find(int x)
{
int r=x;
while(pre[r]!=r)
r=pre[r];//这里是用来查找父亲结点的
int i=x,j;
{
j=pre[i];
pre[i]=r;
i=j;
}//这里是用来就行路径压缩
return r;//返回
}
并的代码:
void merge(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
pre[fx]=fy;
}
这里就是去比较x和y的父亲节点是否相同,如果不相同,那么把其中一个作为另一个的父亲即可。
那接下来看一下完整代码:
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
int pre[1007];
int find(int x)
{
int r=x;
while(pre[r]!=r)
r=pre[r];
int i=x,j;
{
j=pre[i];
pre[i]=r;
i=j;
}
return r;
}
void merge(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
pre[fx]=fy;
}
int main()
{
int n,m,count;
while(cin>>n)
{
count=-1;
int x,y;
if(n==0)
return 0;
for(int i=1;i<=n;i++)
pre[i]=i;
cin>>m;
for(;m>0;m--)
{
cin>>x>>y;
merge(x,y);
}
for(int i=1;i<=n;i++)
{
if(pre[i]==i)
count++;
}
cout<<count<<endl;
}
return 0;
}
千万千万不要忘记,初始化,令每一个点的初始父亲结点是他自己。可能对count为啥是-1,有人不太明白。其实就是,三个点,需要两条路,这个意思。