概念
最小环:指一个由n个点构成的图中,边权和最小的环。(n >= 3)。
最小环分为有向图最小环和无向图最小环。
方法
n为点的个数,m为边的条数。
三种解法:
一、暴力
时间复杂度O(n2 m)
每次枚举删一条边line,这条边的两个端点为u,v,求取在删除这条边后,u,v的最短距离dis,则含有这条被删除的边的最小的环的长度为 dis + line
二、Dijkstra
时间复杂度O(m(n+m)lognm(n + m)log nm(n+m)logn)
还是枚举删边,只是用dijkstra优化了求u,v最短距离的过程
三、Floyd
时间复杂度O(n3)
设原图的点uuu与点vvv之间的边的边权为val(u,v)val(u,v)val(u,v)
首先,我们先来看到Floyd算法,我们知道Floyd这个算法,在最外层循环枚举到K时(尚未开始第K次循环),最短路dis数组中,dis[u][v]dis[u][v]dis[u][v]表示的是从u点到v点且仅经过编号在[1,K)区间中的点的最短路。
由最小环的定义可以知道至少有三个顶点,设其中编号最大的顶点为w,环上与w相邻两侧的两个点为u,v,那么在最外层循环枚举到k = w时,该环的长度即为dis[u][v]+val(v,w)+val(w,u)dis[u][v] + val(v, w) + val(w, u)dis[u][v]+val(v,w)+val(w,u)。
所以在循环时对于每一个 kkk ,枚举满足i<k,j<ki < k, j < ki<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/