信奥赛C++提高组csp-s之并查集(案例实践)1

题目描述
某市调查城镇交通状况,得到现有城镇道路统计表。表中列出了每条道路直接连通的城镇。市政府 "村村通工程" 的目标是使全市任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要相互之间可达即可)。请你计算出最少还需要建设多少条道路?
输入格式
输入包含若干组测试数据,每组测试数据的第一行给出两个用空格隔开的正整数,分别是城镇数目 n n n 和道路数目 m m m ;随后的 m m m 行对应 m m m 条道路,每行给出一对用空格隔开的正整数,分别是该条道路直接相连的两个城镇的编号。简单起见,城镇从 1 1 1 到 n n n 编号。
注意:两个城市间可以有多条道路相通。
在输入数据的最后,为一行一个整数 0 0 0,代表测试数据的结尾。
输出格式
对于每组数据,对应一行一个整数。表示最少还需要建设的道路数目。
输入输出样例 1
输入 1
4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0
输出 1
1
0
2
998
数据规模与约定
对于 100 % 100\% 100% 的数据,保证 1 ≤ n < 1000 1 \le n < 1000 1≤n<1000 。
代码实现
cpp
#include <bits/stdc++.h>
using namespace std;
int n, m;
int fa[1010]; // 并查集数组,存储每个节点的父节点
// 查找操作:找到x的根节点,并进行路径压缩
int find(int x) {
if(fa[x] != x) {
fa[x] = find(fa[x]); // 路径压缩,将查找路径上的节点直接连接到根节点
}
return fa[x];
}
// 合并操作:将x和y所在的集合合并
void unionSet(int x, int y) {
int rootx = find(x);
int rooty = find(y);
if(rootx == rooty) return; // 如果已经在同一集合,无需合并
fa[rooty] = rootx; // 将一个集合的根节点连接到另一个集合的根节点
}
int main() {
while(true) {
cin >> n; // 读取城镇数量
if(n == 0) break; // 输入0表示结束
cin >> m; // 读取道路数量
// 初始化并查集,每个城镇的父节点初始化为自己
for(int i = 1; i <= n; i++) {
fa[i] = i;
}
// 处理每条道路
for(int i = 1; i <= m; i++) {
int x, y;
cin >> x >> y;
unionSet(x, y); // 合并两个城镇所在的集合
}
// 统计连通分量(集合)的数量
int cnt = 0;
for(int i = 1; i <= n; i++) {
if(fa[i] == i) { // 如果节点的父节点是自己,说明它是根节点
cnt++;
}
}
// 需要建设的道路数 = 连通分量数 - 1
cout << cnt - 1 << endl;
}
return 0;
}
功能分析
核心思路:
- 问题转化:将城镇视为节点,道路视为边,问题转化为求连通分量的数量
- 关键观察:如果有k个连通分量,那么需要k-1条道路就能将它们全部连接起来
算法步骤:
- 初始化:每个城镇自成一个集合
- 合并操作:对于每条道路,将相连的两个城镇所在的集合合并
- 统计连通分量:遍历所有城镇,统计根节点的数量
- 计算结果:连通分量数-1即为需要新建的道路数
各种学习资料,助力大家一站式学习和提升!!!
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"########## 一站式掌握信奥赛知识! ##########";
cout<<"############# 冲刺信奥赛拿奖! #############";
cout<<"###### 课程购买后永久学习,不受限制! ######";
return 0;
}
- 一、CSP信奥赛C++通关学习视频课:
- C++语法基础
- C++语法进阶
- C++算法
- C++数据结构
- CSP信奥赛数学
- CSP信奥赛STL
- 二、CSP信奥赛C++竞赛拿奖视频课:
- 信奥赛csp-j初赛高频考点解析
- CSP信奥赛C++复赛集训课(12大高频考点专题集训)
- 三、csp高频考点知识详解及案例实践:
- CSP信奥赛C++之动态规划
- CSP信奥赛C++之标准模板库STL
- 信奥赛C++提高组csp-s知识详解及案例实践
- 四、考级、竞赛刷题题单及题解:
- GESP C++考级真题题解
- CSP信奥赛C++初赛及复赛高频考点真题解析
- CSP信奥赛C++一等奖通关刷题题单及题解
详细内容:
1、csp/信奥赛C++,完整信奥赛系列课程(永久学习):
https://edu.csdn.net/lecturer/7901 点击跳转



2、CSP信奥赛C++竞赛拿奖视频课:
https://edu.csdn.net/course/detail/40437 点击跳转

3、csp信奥赛高频考点知识详解及案例实践:
CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转
CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转
信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html
4、csp信奥赛冲刺一等奖有效刷题题解:
CSP信奥赛C++初赛及复赛高频考点真题解析(持续更新):https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转
CSP信奥赛C++一等奖通关刷题题单及题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转
5、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转
· 文末祝福 ·
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"跟着王老师一起学习信奥赛C++";
cout<<" 成就更好的自己! ";
cout<<" csp信奥赛一等奖属于你! ";
return 0;
}