题目来源:CSES 1666。本 Lab 使用下述本地数据范围与规范化输出。原题允许任意有效答案,本地评分按明确的规范化规则比较;样例为课程样例。
学习目标
前置知识
先阅读 6.3 图的遍历与连通性。环境需要 Node.js、pnpm 和支持 C++17 的编译器;Make 可选,可用下方 pnpm 命令替代。
题目
给定 n 座城市和已有双向道路,需要添加尽量少的道路,使任意两座城市都能互相到达。设现有分量各自的最小城市编号从小到大为 r1..rk,本 Lab 要求依次添加 r1-r2、r1-r3、...、r1-rk,输出该规范方案。
输入格式
第一行 n m,随后 m 行已有道路 u v。
数据范围
本 Lab:1 <= n <= 100000,0 <= m <= 200000,城市编号 1..n;无自环、无重边。
输入为单组有效数据,所有整数和命令按空白分隔。自动评分不包含非法编号、非法命令或违反上述限制的图,不需要额外输出输入校验提示。
输出格式
第一行最少新增道路数 k-1。随后 k-1 行按上述顺序输出道路两个端点。原图已连通时仅输出 0。
只向标准输出写入答案;调试信息写入标准错误。按题面规定分行,评分按空白分隔的 token 比较。
样例
样例输入
6 3
1 3
2 4
5 6样例输出
2
1 2
1 5三个分量是 {1,3}、{2,4}、{5,6},代表为 1、2、5。新增 1-2 和 1-5 即可连通全部城市。
实现任务
修改本题目录中的 student/main.cpp,完成 TODO 标记的算法。输入输出骨架可以保留,完整参考实现单独位于 solution/main.cpp。
- 找出每个分量的最小城市编号,按编号升序排列。
- 把其余分量的代表城市都连接到最小代表城市,输出固定顺序。
正常、边界与错误情况
- 正常情况:按题目定义处理全部输入,输出与输入边的排列顺序无关。
- 只有一个城市:输出 0。
- 空图:新增 n-1 条道路。
- 顶点编号交错的分量:代表必须是每个分量的最小顶点。
- 常见错误:输出 k 条道路不是最优;原题任意最优方案可以合法,但本地必须满足题面规范顺序。
- 非法输入不在评分范围;不要在标准输出中添加提示词、调试标记或额外解释。
运行与评分
在本 Lab 目录执行:
make doctor
make run
make run CASE=001-sample
make score未安装 Make 时,在仓库根目录执行:
pnpm lab:doctor -- labs/chapter-06/exercise/E-06-20-building-roads
pnpm lab:run -- labs/chapter-06/exercise/E-06-20-building-roads
pnpm lab:run -- labs/chapter-06/exercise/E-06-20-building-roads --case 001-sample
pnpm lab:score -- labs/chapter-06/exercise/E-06-20-building-roads本题有 20 组测试,每组 5 分,总分 100。起始代码可以编译,但尚未实现完整算法;满分需补齐 TODO。作者检查参考解、骨架与预期输出可使用 pnpm lab:verify -- labs/chapter-06/exercise/E-06-20-building-roads。
正确性说明
一条新增道路最多使分量数减少 1,所以 k 个分量至少需要 k-1 条道路。以一个分量为中心连接其他所有分量恰好使用 k-1 条,且图变连通,因此达到下界。
复杂度分析
按城市编号递增启动遍历时代表天然有序,总时间 O(n+m),空间 O(n+m)。
完成清单
思考与复盘
- 为什么新增道路连接同一分量内部的两点不能帮助达到最少条数?
- 将代表连接成一条链是否也最优?它是否符合本 Lab 的输出规则?