1. 程式人生 > 實用技巧 >【學習筆記】二分圖匹配——匈牙利演算法 By 5ab as a juruo.

【學習筆記】二分圖匹配——匈牙利演算法 By 5ab as a juruo.

目錄

關於二分圖

如果你學習圖論,這個詞肯定聽說過,即使沒有系統學習過二分圖及其相關演算法。

那到底什麼是二分圖呢?簡單來說,就是將一張圖的節點分成兩部分,使得所有的邊都只從一邊連向另一邊,不存在兩個節點都在同一部分的邊。

舉個例子,一條大河波浪寬,兩邊各有一些村子,村子與村子之間只有跨江的橋連線。那麼如果將村子作為節點,而橋作為邊,那麼這就是一張二分圖。

二分圖有許多優美的性質和特點,這使得由二分圖而演化出來的演算法比較多。

二分圖匹配

什麼是匹配呢?就是將二分圖中的一些邊選出來,使得每一條邊的兩個節點都互不相同。

舉個例子,現在有一些 ♂ 和一些 ♀ 在找物件,你將這些人放在一起要組 CP。

但是,只有其中的一部分是 互相 有好感的,可以組建 CP。同時,一個人只有可能在一對 CP 內。使得 CP 的數量最多的方案就是二分圖最大匹配。


那麼,怎麼計算二分圖最大匹配呢?

我們先來想一個很暴力的做法——能配對就配對。儘可能將前面的組成 CP,後面的有就組,沒有隻能幹啃狗糧了 QAQ。

下面是已經給出的湊 CP 名單,我們要本著 給結婚辦事處添麻煩 救助單身狗的原則湊儘可能多的 CP。

(注:藍色表示 \(\color{blue}{\text{♂}}\),紅色表示 \(\color{red}{\text{♀}}\),黑色邊表示 CP)


\[\Huge{\text{第一幕}} \]

男1:我先選 CP 嗎?那可太好了!

管理員:對,按照慣例,先由編號小的開始。(低語,略微轉頭)不過貌似從最後一個開始選也一樣吧。

男1:啊選哪個呢?點兵點將……啊啊啊,選擇困難症受不了啊!乾脆就選第一個吧!

女1:你確定?你不是之前還跟我吵過架嗎?還揚言要放火燒掉我的家,不是嗎?呵呵……

男1:那我選誰啊?你個糟老婆子,就會比比叨叨比比叨叨……

女1:你再罵?!

管理員:好,很好,你們兩個就請先下臺吧。後面有事會找你們的。

男1:哼,就會說風涼話。

男2:然後……就是我了嗎?管理員?

管理員:嗯,按照慣例是的,你要選誰呢?

男2:輪到我了……顯然女1啊!誒,她人呢?

女1:你眼睛瞎了嗎?!我看你是在想 peach!

男2:這還不好辦,讓男1再去找一個……

男1:你彳亍你找啊!我就這一個青梅竹馬,別想搶!

男2:(尷尬而不失猥瑣地笑)好吧,反正我心中還有一個人選,不是嗎,女3?

女3:(臉頰泛紅)是啊……那就這樣吧。

管理員:所有候選人員注意!如果你接下來的物件是已經被挑選的,請慎重考慮那些已經組好的 CP 的去向,否則不要提出這種想法!

===

\[\Huge{\text{第二幕}} \]

男3:好哇,速度不慢嘛!我康康……不就是女2嘛!我們倆關係可好了,比如……

管理員:你可快點!前面那麼快不是你慢的藉口!

男4:【內心獨白】好傢伙!照男3的說法,那我唯一的選擇女2不就 ×× 了嗎?但是別人也就這一個選擇……啊這,好吧,難道就要這樣吃一輩子狗糧了嗎,呵呵。

管理員:下一個是……

男4:我沒有選擇了,註定單身啊(嘆氣帶笑)。

男5:啊?我啦?好快的車車。首選是:女……

【內心獨白】

不對!如果是女3,那麼男2將要去搶女1,但是這樣男1就要找我算賬啦!怎麼辦?

對啊!我不是還有候選女4嗎?看來渣男和渣女必然在一起啊,呵呵。

男5:……4!就是你了!

管理員:【內心獨白】!可以啊,人品不咋地,但是還有一點腦子可以使。

管理員:好了,這樣就行了。CP 的數量達到最大值!本次配對活動順利成功!

男4:你確定?這樣如果真的是最大值,那我無話可說。但是如果不是,你必須給我個說法!

管理員:好啦好啦,我跟你 gang 啦!這其實就是——匈牙利演算法!二分圖最大匹配的標準流程!

演算法講解

在這之前,先介紹一下增廣路的概念。注意,這裡的增廣路和網路流裡的增廣路不同,但本質都是為了增加可行答案的最大值。

這裡的增廣路滿足:相鄰的兩條邊,必有一條是匹配邊,另一條是未匹配邊,且第一條邊和最後一條邊是未匹配邊,且兩個端點都沒有被匹配過。

我們只要找到增廣路,並將其每一條邊取反,就可以增加答案。

一個標準的匈牙利演算法執行以下流程:

  1. 找到第一個沒有匹配的左端節點,如果沒有跳至第 4 步;

  1. 選取第一條沒有匹配的這個點的一條出邊,如果沒有跳至第 1 步;

  1. 如果這條邊是一條增廣路的起點,則將這條增廣路上的所有邊取反,返回第 2 步;

  1. 統計並輸出。

那麼,這個演算法為什麼是對的呢?反正我不知道

這是一個基於貪心的做法,複雜度為 \(O(nm)\),因為最多有 \(n\) 條增廣路,且每條增廣路按照 DFS 的方式搜尋複雜度為 \(O(m)\)

模板程式碼

輸入格式

第一行兩個正整數 \(n\)\(m\),分別表示節點數為 \(2n\),邊數為 \(m\),節點編號為 \(1,2,3,\cdots,2n-1,2n\),邊均從前 \(n\) 個點連向後 \(n\) 個點。

接下來 \(m\) 行,每行兩個整數 \(a_i\)\(b_i\),表示第 \(i\) 條邊的兩個端點。

輸出格式

輸出最大匹配。

Code

咕咕咕

例題

待填……