1. 程式人生 > 其它 >Floyd求最小環

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)$ ,大部分題都沒戲

同時因為使用鄰接表存圖,所以記憶體也堪憂