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