题目来源:改编自 LeetCode 1761:一个图中连通三元组的最小度数。原题使用函数接口和从
1开始的节点编号;本 Lab 改为标准输入输出和从0开始的顶点编号,核心定义与返回结果保持一致。
学习目标
前置知识
开始前先阅读 6.1 图的基本概念中的度与子图,以及 6.2 图的存储结构中的邻接矩阵部分。运行 make doctor 可以检查 C++17 编译环境。
题目
给定一张简单无向图。一个连通三元组由三个不同顶点组成,并且这三个顶点之间两两有边,也就是它们共同构成一个三角形。
连通三元组的度数是一端位于三元组内、另一端位于三元组外的边数。请输出图中所有连通三元组的最小度数;如果图中不存在连通三元组,输出 -1。
不要误解“连通三元组”
三个顶点之间存在一条路径还不够。例如只有边 0-1 和 1-2 时,三个顶点虽然位于同一连通分量中,但 0 与 2 不相邻,因此不构成题目所说的连通三元组。
输入格式
第一行包含两个整数 n m,分别表示顶点数和边数。顶点编号为 0 到 n-1。
接下来 m 行,每行包含两个整数 u v,表示无向边 {u,v}。输入保证:
2 <= n <= 400;0 <= m <= n(n - 1) / 2;0 <= u, v < n;u != v;- 不包含重复边。
输出格式
输出一个整数:所有连通三元组中的最小度数;不存在连通三元组时输出 -1。
样例输入
6 6
0 1
0 2
2 1
3 0
4 1
2 5样例输出
3顶点 0、1、2 两两相邻,是唯一的连通三元组。边 3-0、4-1、2-5 各连接三元组内外,因此该三元组的度数为 3。
关键推导
设三元组为 {a,b,c}。如果分别统计三个顶点在整张图中的度,则
degree[a] + degree[b] + degree[c]同时包含内部边和外部边。三元组内部恰好有三条边:a-b、a-c 和 b-c。每条内部边会在两个端点的度中各出现一次,因此内部边一共贡献 6。所以:
trioDegree = degree[a] + degree[b] + degree[c] - 6这里减去的 6,是三条内部边在三个顶点的度数和中产生的 6 个计数;不能只按内部边的条数减去 3。
任务
- 创建
n × n的邻接矩阵和长度为n的度数数组; - 对每条无向边
(u,v),同时设置matrix[u][v]与matrix[v][u],并增加两个端点的度; - 只枚举满足
a < b < c的顶点三元组,避免重复检查同一组顶点; - 通过三个矩阵单元判断它们是否两两相邻;
- 对每个合法三元组计算
degree[a] + degree[b] + degree[c] - 6,维护最小值; - 如果枚举结束后没有找到三元组,输出
-1。
正常、边界与错误情况
| 情况 | 预期行为 |
|---|---|
| 只有一个三角形 | 输出该三元组连接外部的边数 |
| 存在多个三角形 | 比较所有三元组,输出最小度数 |
| 三角形与其他顶点完全分离 | 该三元组度数为 0 |
| 完全图 | 每组三个顶点都是候选,仍只输出最小值 |
| 只有路径或树 | 不存在两两相邻的三个顶点,输出 -1 |
n = 2 或无边图 | 不可能组成三元组,输出 -1 |
| 自环、重复边或越界顶点 | 自动评分输入不会出现;无需额外校验,也不要输出错误提示 |
运行与评分
在本 Lab 目录执行:
make doctor
make run
make run CASE=001-sample
make score未安装 Make 时,在仓库根目录执行:
pnpm lab:doctor -- labs/chapter-06/exercise/E-06-02-minimum-trio-degree
pnpm lab:run -- labs/chapter-06/exercise/E-06-02-minimum-trio-degree
pnpm lab:score -- labs/chapter-06/exercise/E-06-02-minimum-trio-degree完成清单
复杂度分析
初始化邻接矩阵需要 O(n²) 时间,读取边需要 O(m) 时间,枚举顶点三元组需要 O(n³) 时间,因此总时间复杂度为 O(n³ + m)。邻接矩阵占用 O(n²) 空间,度数数组占用 O(n) 空间,总空间复杂度为 O(n²)。
在这一约束下选择邻接矩阵,是用较高的空间消耗换取任意两点邻接关系的 O(1) 查询。
思考与复盘
- 为什么枚举时限制
a < b < c不会漏掉任何三元组? - 为什么公式需要减去
6?如果只减去3,会把哪部分内部边贡献误算为外部边? - 在完全图
K_n中,任意连通三元组的度数是多少?尝试从公式和直接数边两个角度推导。 - 如果
n增长到100000,邻接矩阵和三重枚举分别会遇到什么问题?可以如何利用边集或邻接表减少候选三元组?