匈牙利演算法

2021-05-27 09:31:27 字數 2848 閱讀 9697

匈牙利演算法用來解決二分圖最大匹配問題。乙個典型的最大匹配問題的描述如下:乙個公司有n項工作,m個員工。每個員工能勝任n項工作中的幾項(0~n)工作。問題是,如何分配才能使得被處理的工作數最大。當然,如果公司裡人員很多,每項工作都有很多員工可以勝任,那麼使每項工作都有人處理的方案是顯而易見的。但遇到人員稀少,幾個專案可能只有乙個人才能勝任的情況下,問題不再簡單。假如a能處理a,b問題,b能處理b,這時如果讓a處理了b,a便沒人勝任了。當問題擴充到很大時,將會是很麻煩的問題。

二分圖:二分圖是一種特殊的圖。圖中的頂點可以分為兩個不相交的集合(a,b)。且圖中每條邊兩端的頂點分別屬於兩個集合。在上面的例子中,員工集合是a,工作集合為b。員工勝任工作的對應關係即為邊的關係。

最大匹配:二分圖g的乙個子圖m中,如果任意兩條邊沒有公共頂點,或者說沒有乙個頂有條路,則稱其為g的匹配。對於上例中,只要分配方案中,乙個工作人員只完成一項工作,一項工作只由乙個人員完成,則稱為乙個匹配。最大匹配是指在所有匹配中,邊數最多的一種匹配。即能完成工作最多的分配方案或者參加工作人員最多的方案。如果匹配中所有頂點都和某個邊連著,則稱為完美匹配完備)。

簡單的看,求最大匹配的方法就是找出所有的匹配,然後找出匹配中最多邊數的匹配,即為最大匹配。不過這樣演算法的時間複雜度大的讓人髮指。匈牙利演算法又稱增廣路法。增廣路是該演算法的精髓。

增廣路:這個定義維基給的比較水「若p是圖g中一條連通兩個未匹配頂點的路徑,並且屬於m的邊和不屬於m的邊(即已匹配和待匹配的邊)在p上交替出現,則稱p為相對於m的一條增廣路徑。」讀了很多遍都感覺很饒。增光路的存在是相對某個給定的匹配(m)。路徑p是增廣路的充分必要條件:

1.起點和終點都不屬於m。

2.p中任意兩個相鄰的邊,乙個屬於m,乙個不屬於m。

由此,可以推出增廣路的幾條性質:

1.p的路徑長度必定為奇數,第一條邊和最後一條邊都不屬於m。

2.將m和p進行異或操作(去同存異)可以得到乙個更大的匹配m』。

3.m為g的最大匹配當且僅當不存在m的增廣路徑。

回到匈牙利演算法,由2,3性質,我們只要找到圖的一條增廣路作為乙個新的匹配繼續找其增廣路,重複下去最後總能找到其最大匹配。

原理搞清楚了,接下來就是**實現了:

/*以下**出自 www.nocow.com*/
#include#includebool g[201][201];      //圖  

int n,m,ans;

bool b[201]; //訪問標記

int link[201]; //b集合中與a集合中匹配的頂點

bool init() //錄入圖(這個錄入有些神奇,搞不懂...無視之...)

} return true;

}

bool find(int a) //找從a出發的增廣路,a將是集合a的遍歷

} }

return false;

}

int main()

printf("%d\n",ans);

}}

解釋別人的**是件很繁瑣的事情。理解是乙個步驟,講出來又是乙個步驟。遞迴程式加注釋難以解釋清楚。

程式的流程是遍歷a集合頂點 (*6)因為是從a中遍歷,所以每一次迴圈出的點ai一定是未匹配的點,即一條增廣路的起點。find()的遞迴停止條件分別在(*2)(*4)。如果返回false則說明從ai出發沒有增廣路。如果返回ture要麼是(*4)中link[i]==0,即發現未匹配的點,以該未匹配的點作為增廣路的結尾。要麼遞迴的find(link[i])返回了ture。再來分析遞迴的find(link[i])。link[i]是與bi匹配的aj,如果開始遞迴find(link[i]),說明前面(*3)的條件通過,ai也與bi通路。說明aj與ai共同連線著bi,明顯aj已經參與過find()。重新呼叫find(aj)事,唯一不同的是,bi被標記為了已訪問(*3)。說明本次呼叫aj會忽略bi重新找一條增廣路。如果找到了,則ai->bi->aj->p(由aj出發的增廣路)又構成乙個增廣路。其中,因為aj,ai都連著bi,所以ai->bi->aj的連通性是沒有問題的。這樣增廣路的邊數每次只增加1(其實如果遞迴呼叫了find()相當於拆掉之前匹配好的一條邊,然後用ai形成的邊補回去,如果被拆的aj沒有通過拆別的邊找到新的增廣路,即(*3)是由條件link[i]==0結束,那麼說明aj找到了乙個未匹配點,則邊數+1,匹配數+1)。所以無窮無盡的遞迴說白了就是當前讀入的點和以前的點有共同連線的頂點,如果以前的點能找乙個新的匹配點則把當前點到增廣路中。換到文章開始時的例子中就是先乙個人乙個任務的安排,如果找到乙個人(a)能勝任的任務已經被別人(b)勝任,則看看b還有沒有其他任務可以完成,如果有,則交換a接手b的任務,b去做其他任務,如果b沒有任務可以完成了,則a放棄這個任務,再從下乙個能完成的任務中找。沒有可以勝任的任務時,被完成的工作數不增加。反之說明匹配成功一次。任務+1。最後統計出的資料一定是達匹配數。

恩...絞盡腦汁的把**翻譯了一遍...感覺還是沒說清楚。算了,明天手寫一遍程式就好。恩恩...

選拔賽就開始了啊,黎琦大神我拜拜你了,再別copy**了好不好,到時候搶了人強隊的名額可就是罪過了...誒...蛋疼孩子沒法說啊,沒法說。嘖嘖嘖~

匈牙利演算法

匈牙利演算法 edmonds演算法 步聚 1 首先用 標記x中所有的非m頂點,然後交替進行步驟 2 3 2 選取乙個剛標記 用 或在步驟 3 中用 yi 標記 過的x中頂點,例如頂點xi,如果xi與y為同一非匹配邊的兩端點,且在本步驟中y尚未被標記過,則用 xi 去標記y中頂點y。重複步驟 2 直至...

匈牙利演算法

二分圖匹配的演算法,二分圖就是把圖上的點分成兩個互不相交的點集,而圖中的邊的端點只能分別屬於這兩個點集.二分圖的匹配,就是婚配問題,左邊的點集男性,右邊的點集女性,然後相互配對 一夫一妻 最大匹配就是讓好事最多.匈牙利演算法可以實現這個東西.匈牙利演算法怎麼實現的這個東西.這個比較多.如下 incl...

匈牙利演算法

二分圖又稱作二部圖,是圖論中的一種特殊模型。設g v,e 是乙個無向圖,如果頂點v可分割為兩個互不相交的子集 a,b 並且圖中的每條邊 i,j 所關聯的兩個頂點i和j分別屬於這兩個不同的頂點集 i in a,j in b 則稱圖g為乙個二分圖。給定乙個二分圖g,m為g邊集的乙個子集,如果m滿足當中的...