思路:其实很就是求连通分量的个数,道路就为个数减1,将其放在一个集合中去,其他连通分量都为同一个连通分量的根节点的子树
#include<iostream>
using namespace std;
#define N 1000
int tree[N];//按下标保存下标数字的祖先节点,-1代表下标数字为根节点
int findroot(int x)
{
if (tree[x] == -1)return x;//找到根结点,递归出口
else
{
while (tree[x] != -1)//路径压缩,将子树的子树的那些节点的根节点全被变成这颗树的节点
{
int temp = findroot(tree[x]);//递归的查找到此时x所在树的树根节点
tree[x] = temp;//将x的祖先节点变成树根节点;
return temp;//返回这个根节点
}
}
}
int main()
{
int n, m;
while (cin >> n >> m)
{
if (n == 0)break;
for (int i = 1; i <= n; i++)//一开始所有节点都为单独的根节点
tree[i] = -1;
int a, b;
while (m--)
{
cin >> a >> b;
a = findroot(a);//将a所在树的根节点找出
b = findroot(b);//将b所在树的根节点找出
if (a != b)tree[a] = b;//比较两点的根节点,如果不同,则把a树作为b树的子树,连接到b树的根节点上,建立并查集
}
int ans = 0;
for (int i = 1; i <= n; i++)//最后遍历,tree[i]=-1的为单独的一个连通分量
{
if (tree[i] == -1)
ans++;
}
cout << ans-1 << endl;
}
return 0;
} 其中 findroot函数也可用非递归的形式 int findroot(int x)
{
int ret,t=x,temp;
while(tree[x]!=-1)
{
x=tree[x];
}
ret=x;
x=t;
while(tree[x]!=-1)//路径压缩
{
temp=tree[x];
tree[x]=ret;
x=temp;
}
return ret;
} 
京公网安备 11010502036488号