帶權的二分圖的最優匹配KM演算法
/********************************************************* 演算法引入: 給定一個完全二分圖G=(X∪Y,X×Y),其中邊(x,y)有權w(x,y); 要找一個從X到Y具有最大權和的匹配M,即為二分圖的最優匹配問題; KM(Kuhn_Munkras)演算法求的是完備匹配下的最大權匹配; 演算法思想: KM演算法是通過給每個頂點一個標號(叫做頂標)來把求最大權匹配的問題轉化為求完備匹配的問題的; 設頂點Xi的頂標為A[i],頂點Yi的頂標為B[i],頂點Xi與Yj之間的邊權為w[i,j]; 在演算法執行過程中的任一時刻,對於任一條邊(i,j),A[i]+B[j]>=w[i,j]始終成立; 初始A[i]為與Xi相連的邊的最大邊權,B[j]=0; KM演算法的正確性基於以下定理: 設G(V,E)為二分圖,G'(V,E')為該二分圖的子圖; 如果對於G'中的任何邊<x,y>滿足, A(x)+ B(y)==W[x,y]; 則稱G'(V,E')為G(V,E)的等價子圖或相等子圖(是G的生成子圖); 若由二分圖中所有滿足A[i]+B[j]=w[i,j]的邊(i,j)構成的子圖(稱做相等子圖)有完備匹配; 那麼這個完備匹配就是二分圖的最大權匹配; 因為對於二分圖的任意一個匹配,如果它包含於相等子圖; 那麼它的邊權和等於所有頂點的頂標和; 如果它有的邊不包含於相等子圖,那麼它的邊權和小於所有頂點的頂標和(即不是最優匹配); 所以相等子圖的完備匹配一定是二分圖的最大權匹配; 相等子圖包含原圖的所有的點,相等子圖一定可以找到完備匹配; 相等子圖的完備匹配只需加一些虛擬點可以擴充為完美匹配(記為M); 完美匹配是包含了所有點的匹配,那麼所有點的頂點的標號值都包括進來了; 雖然有些點是0,在這個狀態下,把相等子圖的標號一一對應的標到原圖上去; 原圖的任意一個匹配最多隻能包含原圖的所有頂點; 即任何匹配的權和不可能超過所有標號的和,所以M的和必然是最優的; 演算法改進: 給每個Y頂點一個"鬆弛量"函式slack; 每次開始找增廣路時初始為無窮大; 在尋找增廣路的過程中,檢查(i,j)時,如果它不在相等子圖中; 則讓slack[j]=min(原值,A[i]+B[j]-W[i,j]); 這樣在修改頂標時,取所有的不在交錯樹中的Y頂點的slack值中的最小值作為d值即可; 演算法過程: ①初始化可行頂標的值; ②用匈牙利演算法尋找完備匹配; ③若未找到完備匹配則修改可行頂標的值; ④重複②③直到找到相等子圖的完備匹配; **********************************************************/ #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<climits> #include<algorithm> using namespace std; const int N = 1000; const int INF = 0xffffff; int w[N][N];//權值 int lx[N],ly[N]; //頂標 int linky[N];//記錄與i匹配的頂點 int visx[N],visy[N]; int slack[N];//鬆弛量 int nx,ny;//二分圖兩邊的頂點數 void init() { memset(linky,-1,sizeof(linky));//記錄與i匹配的頂點 memset(ly,0,sizeof(ly));///初始化頂標y為0 for(int i = 0; i < nx; i++) for(int j = 0,lx[i] = -INF; j < ny; j++) { if(w[i][j] > lx[i]) lx[i] = w[i][j];///初始化頂標x為與頂點Xi關聯的邊的最大權 } } bool find(int x)//匈牙利演算法 { visx[x] = true; for(int y = 0; y < ny; y++) { if(visy[y]) continue; int t = lx[x] + ly[y] - w[x][y];//若t==0,則為最大權匹配; if(t==0) { visy[y] = true; if(linky[y]==-1 || find(linky[y])) { linky[y] = x; return true; //找到增廣軌 } } else if(slack[y] > t) slack[y] = t; } return false; //沒有找到增廣軌(說明頂點x沒有對應的匹配,與完備匹配(相等子圖的完備匹配)不符) } int KM() //返回最優匹配的值 { init(); for(int x = 0; x < nx; x++) { for(int i = 0; i < ny; i++) slack[i] = INF;//鬆弛函式初始化為無窮大 while(1) { memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(find(x)) //找到增廣軌,退出 break; int d = INF; for(int i = 0; i < ny; i++) //沒找到,對l做調整(這會增加相等子圖的邊),重新找 { if(!visy[i] && d > slack[i]) d = slack[i]; } for(int i = 0; i < nx; i++)//修改x的頂標 { if(visx[i]) lx[i] -= d; } for(int i = 0; i < ny; i++)//修改y的頂標 { if(visy[i]) ly[i] += d; else slack[i] -= d;//修改頂標後,不在交錯樹中的y頂點的slack值都要減去d; } } } int result = 0; for(int i = 0; i < ny; i++) { if(linky[i]>-1) result += w[linky[i]][i]; } return result; } int main() { //freopen("C:\\Users\\Administrator\\Desktop\\kd.txt","r",stdin); while(~scanf("%d%d",&nx,&ny)) { if(!nx||!ny) break; int a,b,c; while(scanf("%d%d%d",&a,&b,&c),a+b+c) { w[a][b]=c; } printf("%d\n",KM()); } return 0; }
相關推薦
HDU2255 奔小康賺大錢 (帶權二分圖最優匹配) 模板題【KM演算法】
<題目連結> 奔小康賺大錢 Problem Description 傳 說在遙遠的地方有一個非常富裕的村落,有一天,村長決定進行制度改革:重新分配房子。 這可是一件大事,關係到人民的住房問題啊。村裡共有n間房間,剛好有n家老百姓,考慮到每家都要有
UVA1349(帶權二分圖最大匹配 --> KM算法模板)
amp slack == 還需要 構造 有一個 using lac str UVA1349 題意:給定一些有向帶權邊,求出把這些邊構造成一個個環,總權值最小 解法: 對於帶權的二分圖的匹配問題可以用通過KM算法求解。 要求最大權匹配就是初始化g[i][j]為0,直接跑就可以
帶權二分圖最大匹配 P1500
author ges double its 一個 rip const 方式 empty 帶權二分圖最大匹配 P1500 普通的二分圖最大匹配的權值都是1,但是現在我們要解決帶權的。 解決方法有兩個:一個是匈牙利算法但是不會,另一個是最大費用最大流。 建圖方式是這個樣子:
帶權的二分圖的最優匹配KM演算法
/********************************************************* 演算法引入: 給定一個完全二分圖G=(X∪Y,X×Y),其中邊(x,y)有權w(x,y); 要找一個從X到Y具有最大權和的匹配M,即為二分圖的最優匹配問題;
帶權二分圖的最佳匹配(KM演算法)
還是沒看懂一般圖都是最大匹配問題。。怪我太笨了哎~ 先來個看明白了的KM演算法——尋找帶權二分圖的最佳匹配方法 一般對KM演算法的描述,基本上可以概括成以下幾個步驟: (1) 初始化可行標杆 (2) 用匈牙利演算法尋找完備匹配 (3) 若未找到完備匹配則修改可行標杆 (4)
HDU3488 Tour —— 二分圖最大權匹配 KM算法
sed exceptio total icpc def i++ after ive pac 題目鏈接:https://vjudge.net/problem/HDU-3488 Tour Time Limit: 3000/1000 MS (Java/Others) M
[SDOI2017]新生舞會,洛谷P3705,分數規劃+二分圖最優匹配
正題 題目連結點這裡 給出兩個矩陣a,b,都表示i和j之間的權值,要求構造一個排列P,使得最大。 我們來二分一個mid,使得,然後變形金剛,
學習筆記第十二節:二分圖最優匹配
正題 看到這個題目,會覺得可以直接用綠與被綠匈牙利演算法來解決。 但是當我們遇到,“第i個人和第j個物品會產生g[i][j]的價值,求完全匹配的最小价值”的時候。 我們就需要用到二分圖最優匹配的演算法了。 這個演算法的複
HDU2389:Rain on your Parade(二分圖最大匹配+HK演算法)
Rain on your Parade Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 655350/165535 K (Java/Others)Total Submission(s): 5755&nbs
二分圖最大匹配 匈牙利演算法的簡單理解
(本文圖片及被*標註內容來自CSDN部落格:pi9nc) 基本概念—二分圖 二分圖:是圖論中的一種特殊模型。若能將無向圖G=(V,E)的頂點V劃分為兩個交集為空的頂點集,並且任意邊的兩個端點都分屬於兩個集合,則稱圖G為一個為二分圖。 匹配:一個匹配即一個包含若干條邊的集合,且其中任
過山車 (二分圖最大匹配 匈牙利演算法)
開始時比較難理解的演算法 原題:過山車 題意:n個女生,m個男生,每個女生都有幾個固定的可以搭配的男生,有k組搭配總共,輸入a,b代表a女生可以和b男生搭配,問最後最多有幾對搭配。 先附程式碼: int head_g[N]; int now_g;
匈牙利演算法(求二分圖最大匹配的演算法)
匈牙利演算法是由匈牙利數學家Edmonds於1965年提出,因而得名。匈牙利演算法是基於Hall定理中充分性證明的思想,它是二部圖匹配最常見的演算法,該演算法的核心就是尋找增廣路徑,它是一種用增廣路徑求二分圖最大匹配的演算法。 設 G=(V,E) 是一個無向
(通俗易懂小白入門)二分圖最大匹配——匈牙利演算法
二分圖 先介紹一下什麼是二分圖,二分圖也叫二部圖,設G=(V,E)是一個無向圖,如果頂點V可分割為兩個互不相交的子集(A,B),並且圖中的每條邊(i,j)所關聯的兩個頂點i和j分別屬於這兩個不同的頂點集(i in A,j in B),則稱圖G為一個二分圖,如下圖所有的頂點可以分成A,B兩個集合,而
HDU 1853 & HDU 3488【有向環最小權值覆蓋問題 】帶權二分圖匹配 KM演算法
In the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M (M <= 30000) one-way roads connecting them. You are lucky
KM演算法求帶權二分圖的最大匹配(完備匹配)
1.基礎知識普及 二分圖的概念 二分圖又稱作二部圖,是圖論中的一種特殊 模型。 設G=(V,{R})是一個無向圖。如頂點集V可分 割為兩個互不相交的子集,並且圖中每條邊 依附的兩個頂點都分屬兩個不同的子集。則圖G成為二分圖。 通俗來講,二分圖指的是這樣一種
二分圖大合集——二分圖最大匹配(最小覆蓋數),完美匹配以及最優匹配(帶權最大匹配)
二分圖: 定義:二分圖又稱作二部圖,是圖論的一種特殊模型。設G=(V, E)是一個無向圖,如果頂點V可分割為兩個互不相交的子集(A , B),且圖中的每條邊(i, j)所關聯的兩個定點分別屬於這兩個不同的頂點集(i in A, j in B),則稱圖G為一個二
帶權二分圖的最優匹配 Kuhn-Munkres演算法
分工問題如下:某公司有工作人員x1,x2,...,xn,他們去做工作y1,y2,...,yn,每人適合做其中的一項或幾項工作,每個人做不同的工作的效益不一樣,我們需要制定一個分工方案,使公司的總效益最大,這就是所謂最佳分配問題, 它們數學模型如下: 數學模型: G是加權完全二分圖,V(G)的二分圖
帶權二分圖匹配KM演算法
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int IN
km板子(二分圖最大權匹配)
define != tdi push_back air base long temp 匹配 //#pragma comment(linker, "/stack:200000000") //#pragma GCC optimize("Ofast,
[NOI2012]美食節——費用流(帶權二分圖匹配)+動態加邊
最大 set sin 最短路 最大流 pre 可能 題目 不同 題目描述 小M發現,美食節共有n種不同的菜品。每次點餐,每個同學可以選擇其中的一個菜品。總共有m個廚師來制作這些菜品。當所有的同學點餐結束後,菜品的制作任務就會分配給每個廚師。然後每個廚師就會同時開始做菜。廚師