Loading

Floyd求最小环

Floyd求最小环

一、算法描述

在一张有环的图中,通过 \(O(n^3)\) 的时间效率求出边长最小的环

二、原理与正确性推导

前置知识:

\(\text{Floyd}\) 正确性推导:

Floyd的递推公式如下

\[\\dp[i][j]=\min_{1 \le k \le n}(d[i][k]+d[k][j]) \]

所以,当 \(dp[i][k]\)\(dp[k][j]\) 都取最小值时,由公式珂知 \(dp[i][j]\) 会取到最小值

证明:设 \(i\)\(j\) 之间的最短路径上的节点集中(不包含 \(i\)\(j\) ),编号最大为 \(x\)

\[\therefore 当k=x时,d[i][j]一定能得到最小值 \]

\[用强归纳法证明 \]

\[设i到x中间编号最大的是x_1,x到j中间编号最大的是x_2 \]

\[\because x是i到j中间编号最大的 \]

\[\therefore x_1\lt x,x_2\lt x \]

\[\therefore 根据结论,k=x_1时,d[i][k]已取得最小值 \]

\[k=x_2时d[x][j]已取得最小值 \]

\[\therefore 当k=x时,d[i][k]和d[k][j]都已取得最小值 \]

\[\therefore 当k=x时,d[i][j]能取得最小值 \]

\[\tiny Q.E.D \]

既然已经证明了上面的公式是正确的,那么根据公式写出的 \(Floyd\) 算法也应是正确的

我们首先写出 \(Floyd\) 的核心代码

for(int k=1;k<=n;k++)//以k为中转点
	for(int i=1;i<=n;i++)//i为起点
		for(int j=1;j<=n;j++)//j为终点
			d[i][j]=min(d[i][j],d[i][k]+d[k][j]);

对这个算法进行分析珂知

\(Floyd\) 算法枚举第 \(k\) 个中转点时,已经得到了前 \(k-1\) 个中转点的最短路径

\(k-1\) 个点不包括点 \(k\) ,并且他们的最短路径也不经过点 \(k\) (排除起点、终点)

那么我们从前 \(k-1\) 个点中选取两个点 \(i,j\)

由上珂知:由 \(i\)\(j\) 的最短路径已经求出

如果 \(j\) 能到 \(k\) ,且 \(k\) 能到 \(i\)

那么连接 \(i-j-k-i\) ,我们就得到了包含 \(\{i,j,k\}\) 三个点的最小环

最后枚举所有用这个方法算出的最小环,求最小即珂

三、例题及代码

P6175 无向图的最小环问题

由于题目中的 \(1\le n\le 100\) ,我们珂以用时间效率为 \(O(n^3)\)\(Floyd\) 来求最小环

核心代码:

for(int k=1;k<=n;k++){
    for(int i=1;i<k;i++){
        for(int j=i+1;j<k;j++){
            ans=min(ans,dis[i][j]+a[j][k]+a[k][i]);
        }
    }
    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]);
            dis[j][i]=dis[i][j];
        }
    }
}

AC代码:云剪贴板

四、优缺点

优点

代码简单,珂以直接当作模板背下来

缺点

\(O(n^3)\) ,大部分题都没戏

同时因为使用邻接表存图,所以内存也堪忧

posted @ 2022-04-13 21:17  Locked_Fog  阅读(265)  评论(0编辑  收藏  举报