二分圖最佳匹配有匹配後總權值最大和最小兩種,求最佳匹配的一個有效算法是KM算法。KM算法很複雜很費解。現在只能總結步驟。
KM算法步驟( 以下有層次關係,㈠ > 1 > (1) > ① > Ⅰ)
(一) 建圖:所有點分爲兩部分,一部分屬於L端,一部分屬於R端,兩端的點各有n個,現在要爲L端的所有點在R端的點中找它們的匹配,使最後總權值最大或最小,設有一條邊聯通L的i點與R的j點,權值爲w[i][j],設二維數組gragh_m保存圖,graph_m[i][j]= w[i][j]。
(二) 爲每個點設一個頂標,L端的爲pl,R端的爲pr,將pr的全賦爲0,pl全賦爲與這個點聯通的權值最大的邊的權值,例如與L端第i個聯通的最大權值的邊的權值爲m,則pl[i]=m。
(三) 用一個循環枚舉L中的每個點,爲每個點在R中找其最佳匹配
1.設一輔助數組slack(可在全局定義)大小爲n,將slack全賦爲MAX_INT(無窮大)。
2、用一個死循環爲L中的每個點找匹配,直到找到這個匹配時候break掉此循環,
⑴定義兩個數組vl,vr,全賦爲0,分別表示L中的某個點沒有被訪問過和R中的某個點沒有被需要過(需要表示R中的某個點滿足L中的某個點的最佳匹配要求,但被需要不表示最後能肯定配到它)
⑵以當前的爲其找匹配的點作爲實參調用匹配函數match,這裏假定這個點位置爲pos
match 函數體如下:
① 將vl[pos]賦爲1(訪問過…)
② 用個循環枚舉R中的每個點,設當前點爲j,如果這個點還沒有被需要過(vr[j]==0)則執行:定義變量val=pl[pos]+pr[j]-graph_m[pos][j];
如果val==0(滿足匹配條件)
{
Ⅰ.vr[j]=1;
Ⅱ.如果pre[j]==-1或者match(pre[j])==1(pre[j]表示L中與R中j點的匹配點),則pre[j]=pos,返回真。
}
否則如果(val>0)
{
如果val<slack[j],則slack[j]=val;
}
③返回假。
⑶.如果match返回真,break當前循環。
⑷定義變量d=MAX_INT,枚舉R中每個點,如果vr[j]==0(沒被訪問過)並且slack[j]<val,則d賦值爲slack[kj]。
⑸枚舉L中每個點和R中每個點,假設當前點爲j,如果vl[j]=1,則pl-=d;如果vr[j]==1,則pr[j]+=d;
3.將匹配後每個匹配對的權值加起來。
KM算法C++模板,模板的註釋爲上面所描述的步驟
最佳匹配題目
POJ2195 這裏求的是最小匹配,模板的返回值要變成負的,代碼