blog:
以匈牙利演算法
為基礎,改善後用於求解帶權二分圖的求最佳匹配問題
帶權二分圖的邊權重和最大的匹配,如下圖所示,最大和為102
帶權二分圖的邊權重和最大的完備匹配,如下圖所示
顯然,最佳匹配和最大權匹配並不一致,但如果把剩下的邊補上,並且設定權重為零,那麼二者可以統一起來
下面講的km演算法是用來求最佳匹配,而非最大權匹配。
km演算法是一種計算機演算法,功能是求完備匹配下的最大權匹配。
如果不存在完備匹配,那麼演算法會求最大匹配,如果最大匹配有多種,那麼結果是最大匹配中權重和最大的。
在乙個二分圖內,左頂點為x,右頂點為y,現對於每組左右連線xiyj有權,求最大匹配,並且使得該匹配中所有的和是最大。
該演算法是通過給每個頂點乙個標號(叫做頂標)來把求最大權匹配的問題轉化為求完備匹配的問題的。
設頂點的頂標為的頂標為,頂點的頂標為,頂點與之間的邊權為,在演算法執行過程中,對於圖中的任意一條邊,始終成立。
g當中每一條邊有左右兩個頂標,*相等子圖*就是那些頂標和等於邊權重的邊構成的子圖,如下圖綠色加粗線構成相等子圖
km演算法的正確性基於以下的定理:
定理
:若二分圖中,,並且存在某個相等子圖有完備匹配,那麼這個完備匹配就是二分圖的最大權匹配。
證明:因為這個完備匹配存在於相等子圖中,因此,這個匹配所有邊都滿足:,同時由於完備匹配包含所有的頂點,因此這個屬於相等子圖的完備匹配的總權重等於所有頂標的和。
如果這個二分圖存在另外乙個完備匹配,如果它不完全屬於相等子圖,即存在某條邊,那麼該匹配的權重和就小於所有頂標的和,即小於上述屬於相等子圖的完備匹配的權重和。
首先選擇頂點數較少的為x部,初始時對x部的每乙個頂點設定頂標,頂標的值為該點關聯的最大邊的權值,y部的頂點頂標為0。
對於x部中的每個頂點,在相等子圖中利用匈牙利演算法找一條增廣路徑,如果沒有找到,則修改頂標,擴大相等子圖,繼續找增廣路徑。當每個點都找到增廣路徑時,此時意味著每個點都在匹配中,即找到了二分圖的完備匹配。該完備匹配是最大權重的完備匹配,即為二分圖的最佳匹配。
匈牙利演算法對左邊第乙個頂點,在相等子圖中進行增廣路徑搜尋,找到路徑1-c後進行匹配增廣操作,如下圖所示
回答第乙個問題,需要理解如何在保持相等子圖原來的邊符合相等子圖要求的同時,讓新加的邊也滿足相等子圖的要求。
那麼在增廣路徑搜尋時,我們知道,如果下面這些紫色邊任意一條加入相等子圖後,都可以在相等子圖中使用匈牙利演算法找到一條增廣路徑2-a(or 2-b or 2-c-1-a):
km演算法選擇上述三條紫色邊中,頂標和與邊權重差值最小的邊1-a或者2-a,以該最小差值為d
這裡有乙個問題就是為什麼最小那個?首先比這更小了就不能擴大相等子圖了,但是如果大了,就不能保證
總是成立了。比如上圖選擇了2-b邊的差值2,那麼修改頂標值後,1-a有
。而km演算法中需要修改的頂標,是那些在匈牙利演算法增廣路徑搜尋時,產生一棵交錯樹,為了保證
總是成立,交錯樹上所有的頂標都要參與修改。
比如在如上第二個頂點搜尋增廣路徑時,產生如下圖所示的橙色頂標集合:
修改頂標後產生如下圖所示的結果:
在該相等子圖上以頂點2為開始點,搜尋增廣路徑2-a(or 2-c-1-a),進行增廣操作:
同樣對左邊第三個點:
另外乙個問題是為什麼修改橙色頂標而不去修改頂標a(找到最小差對應的邊的右邊頂標)?修改頂標a的值為-1,那麼邊1-a也可以加入相等子圖了。問題就在於能不能保證總是成立,如下圖所示結果,修改頂標a,邊3-a就不滿足該條件了。除非在修改頂標a的同時,增加頂標3的值,但是需要修改的頂標集合需要額外的搜尋演算法,而修改橙色頂標所需要的交錯樹在增廣路徑搜尋時可以一併產生。
#include#include#include#include#include#include#includeusing namespace std;
typedef long long ll;
const int maxn = 3;
const int inf = 0x3f3f3f3f;
int wx[maxn], wy[maxn];//每個點的頂標值(需要根據二分圖處理出來)
int cx[maxn], cy[maxn];//每個點所匹配的點
int visx[maxn], visy[maxn];//每個點是否加入增廣路
int cntx=maxn, cnty=maxn;//分別是x和y的點數
//int map[maxn][maxn] = ,, };//二分圖邊的權值
int map[maxn][maxn] = ,, };//二分圖邊的權值
int minz;//邊權和頂標最小的差值
bool dfs(int u)//進入dfs的都是x部的點
}else if (t > 0)//此處t一定是大於0,因為頂標之和一定》=邊權
}} return false;}
int km()
wx[i] = max(wx[i], map[i][j]);
} }for (int i = 0; i < cntx; i++)//列舉x部的點 }
int ans = 0;//二分圖最優匹配權值
for (int i = 0; i < cntx; i++)
if (cx[i] != -1)ans += map[i][cx[i]];
return ans;
}int n, k;
int main()
匈牙利演算法 KM演算法
匈牙利演算法 求最大匹配,那麼我們希望每乙個在左邊的點都盡量找到右邊的乙個點和它匹配。我們依次列舉左邊的點x的所有出邊指向的點y,若y之前沒有被匹配,那麼 x,y 就是一對合法的匹配,我們將匹配數加一,否則我們試圖給原來匹配y的x 重新找乙個匹配,如果x 匹配成功,那麼 x,y 就可以新增為一對合法...
匈牙利演算法,KM演算法
bool find int x return false 主程式 for i 1 i n i include include include include include include include include include include include include include...
KM演算法板子
原題hdu2255 其實在求最大 最小的時候只要用乙個模板就行了,把邊的權值去相反數即可得到另外乙個.求結果的時候再去相反數即可 最大最小有一些地方不同。include include include include 赤裸裸的模板啊。const int maxn 301 const int inf ...