学习笔记--计算机考研机试指南
题目来源:牛客网
- 预备知识,并查集
- 题目
- 题目分析
- 代码
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.题目
3.题目分析
(1)该问题可以被抽象成在一个图上查找连通分量的个数,然后减一即为最少还需要修多少条路
(2)可以用并查集来完成,初始时,每个结点都是孤立的连通分量,当读入已经建成的边后,将边的两个顶点所在集合合并,表示这两个集合中的所有结点已经连通。
4.代码
#include<stdio.h>
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;
}