今天也開始學習了下二分圖匹配
二分圖匹配是網絡流最大流的一種特殊情況。
二分圖形式類似於下圖
點分為了左右兩部分,兩部分之間的點有若干條線段相連,但在左部分或右部分之間的點沒有線段相連。
好比左邊三位男員工,右邊三位女員工,連線代表着他們之間互有好感233但現在我們需要一男一女一起搭配干活(不累嘛~)於是乎問題來了,最大能搭配幾對互有好感的男女一起去干活。
解決此類 二分圖匹配 的問題,用到的是叫匈牙利算法。
在介紹着算法之前,我們知道二分圖匹配是特殊的最大流問題,也就是說套最大流的模板也能解出來,只要將原圖改成如下即可:
將原圖中的所有無向邊 e 改為有向邊,方向從U到V,容量為1,增加源點 s 和匯點 t ,從s向所有的頂點u∈U連一條容量為1的邊,從所有的頂點v∈V 向 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 }