二分圖匹配之最大匹配——匈牙利算法


今天也開始學習了下二分圖匹配

二分圖匹配是網絡流最大流的一種特殊情況。

二分圖形式類似於下圖

二分圖

點分為了左右兩部分,兩部分之間的點有若干條線段相連,但在左部分或右部分之間的點沒有線段相連。

好比左邊三位男員工,右邊三位女員工,連線代表着他們之間互有好感233但現在我們需要一男一女一起搭配干活(不累嘛~)於是乎問題來了,最大能搭配幾對互有好感的男女一起去干活。

解決此類 二分圖匹配 的問題,用到的是叫匈牙利算法。

在介紹着算法之前,我們知道二分圖匹配是特殊的最大流問題,也就是說套最大流的模板也能解出來,只要將原圖改成如下即可:

將原圖中的所有無向邊 e 改為有向邊,方向從UV,容量為1,增加源點 s 和匯點 t ,從s向所有的頂點uU連一條容量為1的邊,從所有的頂點vV 向 t 連一條容量為1的邊。

Dinic算法是不斷地尋找增廣路然后不斷增廣,直到不存在增廣路停止。

在這個算法里面,我們人為地規定了反向弧,能夠隱蔽地讓計算機對之前錯誤的選擇更改,再加上這里的容量是1,在此,匈牙利算法便是明顯地遇錯就改。

它的思路是:

1.從第一個元素開始進行匹配。

2.遇到左邊某個元素u所要匹配的右邊另一個元素v,但v先前已經被匹配了,於是就嘗試地更改先前和m匹配的左邊元素x,如果能夠改變,就讓u與v元素匹配,而之前的x就和右邊另一個能匹配元素(有連線的)匹配了233(這里可以運用遞歸)

3.如果不能更改,便放棄該元素。

4.重復步驟2,直到最后一個元素。此時的匹配數即為最大。

換句話就是說 有機會就匹配,沒機會創造機會去匹配。

時間復雜度: 
左邊的點的個數n*總邊數m; 
O(nm)。 

 

 1 bool find(int u){    //u為當前正在匹配的左邊元素
 2        for (int v=1;v<=m;v++){    //掃描右邊每個元素v
 3            if (line[u][v]==true && used[v]==false)        
 4                // line[u][v]==true表示元素u和v之間有連線,used[v]表示這個元素的曾是否有過要更改匹配的,這樣可以省下一些時間
 5          {  
 6            used[v]=1;  
 7            if (f[v]==0 || find(f[v])) {   //f[v]表示v元素所匹配的元素
 8              //f[v]==0表示該元素仍未匹配 find(f[v])是去嘗試能否改變匹配j元素的元素的匹配(就是先前匹配j的元素x能否匹配另一個元素)
 9             f[v]=u;  
10            return true;  
11                                              }  
12            }  
13        }  
14      return false;  
15 }  
16 
17 匈牙利算法
匈牙利算法

 主程序里

1 for (i=1;i<=n;i++)  //依次對左邊每個元素進行匹配
2 {  
3     memset(used,0,sizeof(used));    //每一步中清空  
4     if find(i) ans+=1;  
5 }  
主程序

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM