思路:其实很就是求连通分量的个数,道路就为个数减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;
}