题目描述
某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。所有道路都是双向的。
省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。
问最少还需要建设多少条双向道路?
样例
输入格式
第 1 行给出两个正整数,分别是城镇数目 N 和道路数目 M。
随后的 M 行对应 M 条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。
为简单起见,城镇从 1 到 N 编号。
注意:两个城市之间可以有多条道路相通。(超级易错点)
也就是说
3 3
1 2
1 2
2 1
这种输入也是合法的
输出格式
输出一个整数,表示最少还需要建设的道路数目。
算法1
(暴力枚举) $O(blablabla(总之非常大))$
算法(数据结构)2
(并查集) $合并两集合:近乎O(1) 判断是否在统一集合中:O(1)$
blablabla
时间复杂度
参考文献
并查集
C++ 代码
#include<iostream>
using namespace std;
const int N = 1000010;
int p[N];//p[]存储父节点编号
int n,m,ans;//n代表村子,m代表道路数量,ans代表需要新建的道路数量
int find(int x){//并查集必备知识点
if(p[x]!=x) p[x] = find(p[x]);//递归查找父节点
return p[x];
}//查找父节点并进行路径压缩
int main(){
cin>>n>>m;
for (int i = 1; i <= n; i ++) p[i] = i;//初始化并查集
for (int i = 0; i < m; i ++)
{
int a, b;
scanf("%d %d", &a, &b);
if(find(a)!=find(b)) p[find(a)] = find(b);//因为两个村子之间可能会有两条道路,所以这里需要特判
}//合并两集合(连通道路,如果两村子在一个集合中,说明这里两个村子可以互通)
for(int i = 1;i<=n;i++){
if(p[find(i)] == find(i + 1)) continue;//如果两村子在一个集合中,说明两村子是连通的
else{
ans ++;//否则,两村子不连通,新建道路+1
p[find(i)] = find(i + 1);//合并两集合(给这个村子接上道路)
}
}
cout<<ans - 1;
return 0;
}