算法笔记---图论---并查集

学习笔记--计算机考研机试指南

题目来源:牛客网

  1. 预备知识,并查集
  2. 题目
  3. 题目分析
  4. 代码

1.先介绍图论问题中常常使用到的数据结构--集合,及其相关操作—并查集

这种数据结构用来表示集合信息,用以实现如确定某个集合中含有哪些元素、判断某两个元素是否存在同一个元素中、求集合中元素的数量等问题

(关于并查集可以看一下《超有爱的并查集~》这篇文章,作者飘过的小牛,写的很好)

涉及内容,查找结点x所在树的根结点,路径压缩,合并两个集合

查找结点x的根结点及路径压缩代码:

int findRoot(int x){   //查找某个结点所在树的根结点
	if(Tree[x]==-1){
		return x;
	} else{
		int tmp = findRoot(Tree[x]);
		Tree[x] = tmp;//将当前结点的双亲结点设置为查找返回的根结点编号
		return tmp;
	}
}

合并两个集合

int a,b;
scanf("%d%d",&a,&b);
a=findRoot(a);
b=findRoot(b);
if(a!=b){
		Tree[a] = b;
}

2.题目

算法笔记---图论---并查集_第1张图片

3.题目分析

(1)该问题可以被抽象成在一个图上查找连通分量的个数,然后减一即为最少还需要修多少条路

(2)可以用并查集来完成,初始时,每个结点都是孤立的连通分量,当读入已经建成的边后,将边的两个顶点所在集合合并,表示这两个集合中的所有结点已经连通。

4.代码

#include
using namespace std;
#define N 1000
int Tree[N];
int findRoot(int x){   //查找某个结点所在树的根结点
	if(Tree[x]==-1){
		return x;
	} else{
		int tmp = findRoot(Tree[x]);
		Tree[x] = tmp;
		return tmp;
	}
}
int main(){
	int n,m;
	while(scanf("%d",&n)!=EOF&&n!=0){
		scanf("%d",&m);
		for(int i=1;i<=n;i++){
			Tree[i]=-1;  //初始时,所有结点都是孤立的集合,即其所在集合只有一个结点,其本身就是所在树的根结点 
		}
		while(m--){
			int a,b;
			scanf("%d%d",&a,&b);
			a=findRoot(a);
			b=findRoot(b);
			if(a!=b){
				Tree[a] = b;
			}
		}
		int ans = 0;
		for(int j=1;j<=n;j++){
			if(Tree[j]==-1){
				ans++;//统计所有结点中根结点的个数
			}
		}
		printf("%d\n",ans-1);//答案即为在ans个集合间再修建ans-1条道路即可使所有结点连通
	}
	return 0;
}

 

你可能感兴趣的:(算法学习)