圖論演算法----二分圖匹配----匈牙利演算法詳解
阿新 • • 發佈:2019-01-29
一、一些相關概念
1、二分圖的概念:
二分圖又稱作二部圖,是圖論中的一種特殊模型。
設G=(V,E)是一個無向圖。 如果頂點集V可分割為兩個互不相交的子集X和Y,並且圖中每條邊連線的兩個頂點一個在X中,另一個在Y中,則稱圖G為二分圖。 2、判斷二分圖的方法: 一個圖是連通的,可以用如下的方法判定是否是二分圖: (1)在圖中任選一頂點v,定義其距離標號為0,然後把它的鄰接點的距離標號均設為1,接著把所有標號為1的鄰接點均標號為2(如果該點未標號的話),以此類推。 (2)標號過程可以用一次BFS實現。標號後,所有標號為奇數的點歸為X部,標號為偶數的點歸為Y部。 (3)接下來,二分圖的判定就是依次檢查每條邊,看兩個端點是否是一個在X部,一個在Y部。圖中紅色的邊是數量為2的匹配。
4、最大匹配的概念: 選擇邊數最大的子圖M稱為圖的最大匹配問題 若二分圖X部的每一個頂點都與Y中的一個頂點匹配,並且Y部中的每一個頂點也與X部中的一個頂點匹配,則該匹配為完美匹配。 如果一個二分圖,X部中的每一個頂點都與Y部中的一個頂點匹配,或者Y部中的每一個頂點也與X部中的一個頂點匹配,則該匹配為完備匹配。 圖中所示為一個最大匹配,也是完備匹配,但不是完美匹配。
5、增廣路徑的概念:
如圖,增廣路徑為C->I->E->F->A->H。 那麼,增廣路徑有什麼用呢?我們發現,把增廣路徑的所有邊取反(即匹配的變成未匹配,未匹配的邊成匹配), 則子圖M的邊數會加1,當找不到增廣路徑時,這就是最大匹配了。
6、增廣路徑的性質:
(1)增廣路徑的長度必定為奇數,第一條邊和最後一條邊都不屬於M,因為兩個端點分屬兩個集合,且未匹配。
(2)把一條增廣路徑經過取反操作可以得到一個更大的匹配M’。
(3)M為G的最大匹配當且僅當不存在相對於M的增廣路徑。
7、匈牙利演算法:
演算法輪廓:(1)置M為空
(2)找出一條增廣路徑P,通過取反操作獲得更大的匹配M’代替M
(3)重複(2)操作直到找不出增廣路徑為止
我們採用DFS的辦法找一條增廣路徑: 從X部一個未匹配的頂點u開始,找一個未訪問的鄰接點v(v一定是Y部頂點)。對於v,分兩種情況:(1)如果v未匹配,則已經找到一條增廣路
(2)如果v已經匹配,則取出v的匹配頂點w(w一定是X部頂點),邊(w,v)目前是匹配的,根據“取反”的想法,要將(w,v)改為未匹配,(u,v)設為匹配,能實現這一點的條件是看從w為起點能否新找到一條增廣路徑P’。如果行,則u-v-P’就是一條以u為起點的增廣路徑。
程式碼:(有許多寫法)int w[202][202],cx[202],cy[202],nx,ny;
bool visit[202];
bool dfs(int u)
{
for(int i=1;i<=w[u][0];i++){
int v=w[u][i];
if(visit[v]==0){
visit[v]=1;
if(cy[v]==-1||dfs(cy[v])){
cx[u]=v;cy[v]=u;
return true;
}
}
}
return false;
}
int maxmatch()
{
int ans=0;
memset(cx,-1,sizeof(cx));
memset(cy,-1,sizeof(cy));
for(int i=0;i<=nx;i++){
if(cx[i]==-1){
memset(visit,0,sizeof(visit));
ans+=dfs(i);
}
}
return ans;
}
8、匈牙利演算法的時空分析:
時間複雜度:
找一次增廣路徑的時間為:
鄰接矩陣: O(n^2)
鄰接表:O(n+m)
總時間:
鄰接矩陣:O(n^3)
鄰接表:O(n*m)
空間複雜度:
鄰接矩陣:O(n^2)
鄰接表: O(m+n)
二、幾個有關結論 1、最少點覆蓋集的點數就是最大匹配數M。 2、最少邊覆蓋集的邊數=總邊數-最大匹配數 3、最大獨立集點數=總點數-最大匹配數