概念
最小环:指一个由n个点构成的图中,边权和最小的环。(n >= 3)。
最小环分为有向图最小环和无向图最小环。
方法
n为点的个数,m为边的条数。
三种解法:
一、暴力
时间复杂度O(n2 m)
每次枚举删一条边line,这条边的两个端点为u,v,求取在删除这条边后,u,v的最短距离dis,则含有这条被删除的边的最小的环的长度为 dis + line
二、Dijkstra
时间复杂度O(
m
(
n
+
m
)
l
o
g
n
m(n + m)log n
m(n+m)logn)
还是枚举删边,只是用dijkstra优化了求u,v最短距离的过程
三、Floyd
时间复杂度O(n3)
设原图的点 u u u与点 v v v之间的边的边权为 v a l ( u , v ) val(u,v) val(u,v)
首先,我们先来看到Floyd算法,我们知道Floyd这个算法,在最外层循环枚举到K时(尚未开始第K次循环),最短路dis数组中, d i s [ u ] [ v ] dis[u][v] dis[u][v]表示的是从u点到v点且仅经过编号在[1,K)区间中的点的最短路。
由最小环的定义可以知道至少有三个顶点,设其中编号最大的顶点为w,环上与w相邻两侧的两个点为u,v,那么在最外层循环枚举到k = w时,该环的长度即为 d i s [ u ] [ v ] + v a l ( v , w ) + v a l ( w , u ) dis[u][v] + val(v, w) + val(w, u) dis[u][v]+val(v,w)+val(w,u)。
所以在循环时对于每一个 k k k ,枚举满足 i < k , j < k i < k, j < k i<k,j<k的 ( i , j ) (i , j) (i,j), 更新答案即可。
Floyd解法代码
const int maxn = 1e3 + 10;
const int INF = 0x3f3f3f3f;
int val[maxn][maxn]; //边权
int dis[maxn][maxn]; //最短距离
int floyd(int n)
{
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
dis[i][j] = val[i][j];
}
}
int ans = INF;
for(int k = 1; k <= n; k++)
{
for(int i = 1; i < k; i++)
for(int j = 1; j < i; j++)
ans = min(ans, dis[i][j] + val[i][k] + val[k][j]);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
return ans;
}
参考来源
OI wiki
https://oi-wiki.org/graph/min-circle/