真 O n 3 的非遞迴的 KM

2021-10-02 18:32:58 字數 2875 閱讀 6556

2019 年南京 regional 充分暴露了這個問題,市面上大多數標著 o(n

3)

o(n^3)

o(n3

) 的 km 板子實際上是 o(n

4)

o(n^4)

o(n4

) 的,以致選手如果是用了經典書籍上的板子,或者是網上隨便扒的板子,就會 tle。

然後最近做題做到了 km,就想補乙個自己的真·o(n

3)

o(n^3)

o(n3

) 的 km。網上的 o(n

3)

o(n^3)

o(n3

) 也都沒有教程只能自己啃**,就想把思路寫一下。

大二了才會 km 你丟不丟人

乙個簡單粗暴的判斷板子是 o(n

4)

o(n^4)

o(n4

) 還是 o(n

3)

o(n^3)

o(n3

) 的辦法:非遞迴是 o(n

3)

o(n^3)

o(n3

),遞迴(用了匈牙利一樣的東西)是 o(n

4)

o(n^4)

o(n4)。

更加正確的判斷方法:拿去交正確的模板題,比如 uoj#80、2019 南京 regional j(計蒜客復現)。

要解決的是二分圖最大權匹配問題。這是乙個線性規劃問題,它的對偶問題是最小頂標和問題,km 的思路就是計算最小頂標和。

看這位大佬生動的解釋就懂了:

匈牙利是 o(n

2)

o(n^2)

o(n2

) 的,修改頂標也是 o(n

2)

o(n^2)

o(n2

) 的,每個點最多 n

nn 次修改頂標,共 n

nn 個點,因此是 o(n

4)

o(n^4)

o(n4)。

現在是對於左邊的點 i

ii,我們來優化它的匹配過程。按照 o(n

4)

o(n^4)

o(n4

) 的思想,我們是每次匈牙利找增廣路,失敗了就修改頂標。

如果我們預設每一次增廣都會失敗,那麼實際上每一次增廣的目的就成了最小化 d

dd(最小的頂標增量使得相等子圖能新加入一條邊)。我們把這個 d

dd 掛在右邊的結點上,記為 sla

ck

jslack_j

slackj

​,表示增廣路最後到達的右邊結點為 j

jj 時,能達到的最小的 ddd。

那麼這就如同 dijkstra,我們從 i

ii 出發,把右邊的結點的 sla

ck

slack

slac

k 全部鬆弛一遍,然後找到 sla

ck

slack

slac

k 最小的 j

jj,sla

ck

jslack_j

slackj

​ 就是本次的頂標增量。(若 sla

ckj=

0slack_j=0

slackj

​=0 則頂標不動,相當於匈牙利繼續,若 sla

ck

j>

0slack_j>0

slackj

​>

0 相當於匈牙利失敗了要修改頂標。)

然後嘗試匹配 i

ii 和 j

jj。若 j

jj 單身,則牽手成功;若 j

jj 名花有主,則嘗試綠掉原配增廣原配,即從原配出發,把右邊的結點的 sla

ck

slack

slac

k 又鬆弛一遍……

直到最後找到了單身的 j

jj,就增廣成功了。

於是每個 j

jj 只會被嘗試匹配一次,每個原配只會被綠一次增廣一次,這樣就相當於 i

ii 只做了一次如同 bfs 般的多路增廣,所以總時間複雜度為 o(n

3)

o(n^3)

o(n3)。

回頭看我們預設每一次都增廣失敗,實際上如果增廣成功的話就意味著一路 sla

ckj=

0slack_j=0

slackj

​=0,這種情況被包括了。

我覺得把它稱為多路增廣,或者 bfs,都不如 dijkstra 貼切。

upd:區分了左邊點數 nlnl

nl和右邊點數 nrnr

nr

ll lx[maxn]

,ly[maxn]

,slack[maxn]

;int f[maxn]

,pre[maxn]

;// f[y]表示右邊的 y 匹配了左邊的誰

bool vis[maxn]

;ll km()

fo(i,

1,nl)

fo(j,

0,nr)

if(vis[j]

) lx[f[j]]-

=d, ly[j]

+=d;

// 修改頂標

else slack[j]

-=d;

// 用於鬆弛它的頂標已經改了,所以它也要改

}for

(; py; py=pre[py]

) f[py]

=f[pre[py]];

// 修改增廣路

} ll re=0;

fo(i,

1,nl) re+

=lx[i];fo

(i,1

,nr) re+

=ly[i]

;return re;

}int

main()

km演算法的非最優匹配應用

km演算法可以用來求最優匹配,但是,它本身蘊含著複雜的數學原理,我暫時還不知道怎麼理解,僅僅在此提一道非匹配應用。題目 爭奪 題目描述 小y和小p無聊的時候就喜歡玩遊戲,但是每次小p都輸給了小y。終於有一天,你看不過去了,決定幫小p一把。遊戲是這樣的,乙個n m的棋盤 保證n或m中,至少有乙個為偶數...

遞迴 遞迴演算法的非遞迴優化

一 遞迴 在方法內部呼叫自身方法的過程稱為遞迴,下面給出乙個遞迴方法的示例。class program 使用遞迴,實現求前n項和 public static int getsum int n int result getsum n 1 在方法體中呼叫方法本身 return result n 需要注意...

樹的非遞迴

code 資料結構.cpp 定義控制台應用程式的入口點。include stdafx.h include using namespace std typedef char elemtype typedef struct lnode lnode,linkstack 棧 typedef struct b...