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

信奥赛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;
}

功能分析

核心思路:
  1. 问题转化:将城镇视为节点,道路视为边,问题转化为求连通分量的数量
  2. 关键观察:如果有k个连通分量,那么需要k-1条道路就能将它们全部连接起来
算法步骤:
  1. 初始化:每个城镇自成一个集合
  2. 合并操作:对于每条道路,将相连的两个城镇所在的集合合并
  3. 统计连通分量:遍历所有城镇,统计根节点的数量
  4. 计算结果:连通分量数-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;
}
相关推荐
谢娘蓝桥1 天前
adi sharc c/C++ 语言指令优化
开发语言·c++
郑泰科技1 天前
fmm(快速地图匹配)实践:Unknown toolset: vcunk的解决方案
c++·windows·交通物流
nice_lcj5201 天前
数据结构之树与二叉树:重点梳理与拓展
java·数据结构
a3535413821 天前
设计模式-原型模式
开发语言·c++
liulilittle1 天前
libxdp: No bpffs found at /sys/fs/bpf
linux·运维·服务器·开发语言·c++
星火开发设计1 天前
堆排序原理与C++实现详解
java·数据结构·c++·学习·算法·排序算法
CoderIsArt1 天前
常用SCSI数据结构的详细注释和用法
数据结构
福楠1 天前
C++ STL | list
c语言·开发语言·数据结构·c++·算法·list
myloveasuka1 天前
int类型的取值范围(为什么负数比正数表示的范围多一位)
c语言·c++