最小环问题(有向图与无向图的 Floyd 算法解法)
题目描述
给定一个带权有向图(或无向图),图中可能存在正权边或负权边,但不存在负权环。要求找到图中长度最小的环(即所有边权重之和最小的环)。环的长度定义为构成环的所有边的权重总和。如果图中有多个最小环,只需找出任意一个。如果图中不存在任何环,则报告无解。
解题过程
1. 问题理解与建模
- 环的定义:在图中,一个环是指一条至少包含三个顶点(避免两条边形成的“往返”被误认为环)的闭合路径,其起点和终点相同,且路径上除了起点(也是终点)外,其余顶点互不相同。
- 最小环:所有环中,边权总和最小的环。
- 挑战:直接枚举所有可能的环是不可行的,因为环的数量可能是指数级的。
- 关键思路:利用“动态规划”思想,将最小环问题转化为“最短路径”问题的扩展。
2. 核心思路:基于 Floyd 算法的解法
Floyd 算法原本用于求解所有顶点对之间的最短路径。其状态定义为:
令
dist[k][i][j]表示只允许使用顶点1, 2, ..., k作为中间顶点时,从顶点i到顶点j的最短路径长度。
状态转移方程为:
dist[k][i][j] = min(dist[k-1][i][j], dist[k-1][i][k] + dist[k-1][k][j])
在实现时,通常可以省略第一维,直接在二维数组上迭代更新。
如何利用 Floyd 算法求最小环?
-
考虑环上编号最大的顶点
u。那么,从u出发并回到u的最小环,可以由以下两部分构成:- 一条从
u到某个顶点v的路径,且这条路径只经过编号小于u的中间顶点(即1, 2, ..., u-1)。 - 一条从
v直接返回u的边(即边(v, u)的权重)。
- 一条从
-
在 Floyd 算法的迭代过程中,当处理到
k作为最大中间顶点时,dist[i][j]存储的是只经过编号不超过k-1的顶点时,从i到j的最短路径长度。此时,对于所有i < k且j < k(确保k是环上编号最大的顶点),可以通过dist[i][j] + w[j][k] + w[k][i]来检查一个经过k的环。其中w[a][b]是边(a, b)的权重(如果边不存在,则为无穷大)。 -
算法步骤:
- 初始化一个
dist矩阵,dist[i][j]初始化为边(i, j)的权重(无边则为无穷大,i == j时为 0)。 - 初始化一个
min_cycle变量为无穷大。 - 对于
k从 1 到 n(n 为顶点数):- 枚举可能的环:对于所有
i < k且j < k(且i ≠ j),计算cycle_length = dist[i][j] + w[j][k] + w[k][i]。如果cycle_length < min_cycle,则更新min_cycle。 - 执行 Floyd 更新:对于所有
i, j,更新dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])。
- 枚举可能的环:对于所有
- 如果
min_cycle仍为无穷大,则图中无环;否则min_cycle即为最小环的长度。
- 初始化一个
3. 算法正确性分析
-
为什么能保证找到最小环:
由于 Floyd 算法是按顶点编号顺序逐步引入中间顶点,当处理到k时,所有只经过编号小于k的顶点的最短路径已经计算完毕。此时,任何以k为最大编号顶点的环,必然可以被拆解为一条从i到j的路径(只经过<k的顶点)加上边(j, k)和(k, i)。枚举所有这样的i, j即可覆盖所有以k为最大顶点的环。
最终,所有环都会被其最大编号顶点枚举到,因此全局最小环必然被找到。 -
无向图处理:
无向图中每条边相当于两条方向相反的有向边。算法可以直接应用,但需要注意避免将两条边构成的“往返”误判为环(即i直接到j再直接返回i)。由于我们要求i ≠ j,并且在计算cycle_length时,dist[i][j]是只经过<k顶点的最短路径,所以只要dist[i][j]不是直接边,就不会产生这种误判。
4. 时间与空间复杂度
- 时间复杂度:与 Floyd 算法相同,为 O(n³),其中 n 是顶点数。
- 空间复杂度:O(n²),用于存储
dist矩阵。
5. 扩展:记录环的具体路径
如果需要输出最小环的具体顶点序列,可以在 Floyd 更新时,额外维护一个 next[i][j] 数组,记录从 i 到 j 的最短路径上 i 的下一个顶点。在找到更小的环时,根据 next[i][j] 和边 (j, k)、(k, i) 重构环的路径。
6. 总结
该算法巧妙地将最小环问题嵌入到 Floyd 算法的迭代框架中,通过枚举环上最大编号的顶点,利用已计算的最短路径信息来高效计算环的长度。它适用于边权可为正或负(但不能有负权环)的稠密图,是一种简洁而经典的最小环求解方法。