二分图匹配--匈牙利算法
文章目錄
- 二分圖:
- 匹配
- 匈牙利算法
- 代碼:
二分圖:
二分圖是一個無向圖,點集分成子集X和Y,圖中每一條邊都是一邊在X一邊在Y
當且僅當無向圖G的每一個回路次數都是偶數時(包括0),G就是一個二分圖
匹配
介紹完二分圖后我們看看匹配
匹配:如果任意兩個邊的端點都不相同,我們就稱之為匹配。匹配是邊的集合
最大匹配:所含匹配邊數最多的匹配
完美匹配:在一次匹配中,所有的頂點都是匹配點
完美匹配一定是最大匹配,但是反過來不一定
匈牙利算法
以上講的均為離散知識,現在開始講算法
交替路:從一個未匹配點開始,按照非匹配邊,匹配邊,非匹配邊。。。。這樣的順序形成的路徑
增廣路:從一個未匹配點開始,走交替路,如果途中經過另一個未匹配點,則這條交替路叫做增廣路
增廣路特點:非匹配邊比匹配邊多一條
算法核心就是尋找增廣路徑,直到沒有
匈牙利算法尋找最大匹配,就是通過不斷尋找原有匹配M的增廣路徑,因為找到一條M匹配的增廣路徑,就意味著一個更大的匹配M ’ ,其恰好比M多一條邊。這樣不斷更新,找不到就是最大情況
過程:
一開始隨便選一個未匹配點,先是匹配(x1,y1),標記,然后給x2匹配,匹配(x2,y2),這樣就形成匹配M,有兩條邊,目前沒問題
然后x3匹配,發現y1已經被x1搶占了,然后x3橫刀奪愛搶走y1,x1悲恨交加只能找下一個,然后把x2的對象y2也搶了,x2也只能順位找y5,(這是個遞歸的過程,直到匹配到未被搶占的),這就形成匹配M1
剛才的爭執過程(x3,y1,x1,y2,x2,y5),這就是匹配M的增廣路
發現增廣路就說明有更優的情況,所以我們由匹配M擴展到現在的M1
然后將x4加入,一次類推
如果爭執過程中,最后一個人沒找到對象怎么辦?那這整個搶奪過程就算是失效的
代碼:
我珍藏多年的模板
#include<iostream> #include<cstring> using namespace std; const int maxn = 3; int n = maxn, m = maxn; int Map[maxn][maxn];//map[i][j]=1表示X部的i和Y部的j存在路徑,是否可以匹配 int cx[maxn], cy[maxn]; bool vis[maxn]; //cx[i]表示X部i點匹配的Y部頂點的編號 //cy[i]表示Y部i點匹配的X部頂點的編號bool dfs(int u)//dfs進入的都是X部的點 {for (int v = 0; v < n; v++)//枚舉Y部的點,判斷X部的u和Y部的v是否存在路徑{//如果存在路徑并且還沒被標記加入增廣路if (Map[u][v] && !vis[v])//vis數組只標記Y組{//標記加入增廣路vis[v] = 1;//如果Y部的點v還未被匹配//或者已經被匹配了,但是可以從v點原來匹配的cy[v]找到一條增廣路//說明這條路就可是一個正確的匹配//因為遞歸第一次進入dfs時,u是未匹配的//如果v還沒有匹配對象,即和它相連的所有邊都不在,已經選擇的匹配邊集合M(M\in E)中,這時就找到了u-v增廣路徑//如果v已經有匹配對象了,那么u-v是一條未選擇的邊,//而v-cy[v] \in M 則是一條已經選擇的邊, dfs(cy[v])從cy[v]開始搜索增廣路徑//如果新的v'沒有匹配對象,那么u-v-cy[v]-v'就是一條增廣路徑,//如果v'已經有匹配對象了,那么根據匹配是唯一的,//cy[v]-v'一定不在已經選擇的邊中(和cy[v]-v沖突),//u-v-cy[v]-v'-cy[v']符合增廣路徑對邊順序的要求,繼續利用dfs(cy[v'])搜索u-v-cy[v]-v'-cy[v']-下面的點//當搜索到增廣鏈時,如u-v-cy[v]-v',那么經過遞歸的匹配調整和return 1,進行匹配增廣操作,假設dfs0 是main調用的dfs算法,dfs1是dfs0調用的dfs算法//在dfs1中進行cy[v]-v'的匹配,因為dfs1返回1,因此在dfs0中進行u-v的匹配,匹配增廣操作的結果是{cy[v]-v}->{u-v,cy[v]-v'}//如果在一個dfs(k)自調用的dfs(k+1)中,遍歷所有的v(k+1),要么已經有匹配點了,要么和輸入u(k+1)沒有連接可能,這時搜索終止,說明不存在經過u(k+1)的增廣鏈,返回0//而在main調用的dfs(0)中,調用的dfs(1)返回的都是0,而且v都是已經有匹配了,那么不存在從該點出發的增廣鏈,那么就該點就不在最大匹配當中//為什么找不到增廣鏈就不在最大匹配當中呢?感覺可以用反證法證明,博客中下面內容可能有更新這方面的思考if (cy[v] == -1 || dfs(cy[v])){cx[u] = v;//可以匹配,進行匹配cy[v] = u;return 1;}}}return 0;//不能匹配 } int maxmatch()//匈牙利算法主函數 {int ans = 0;//匹配清空,全部置為-1memset(cx, -1, sizeof(cx));memset(cy, -1, sizeof(cy));for (int i = 0; i < n; i++){if (cx[i] == -1)//如果X部的i還未匹配{memset(vis, 0, sizeof(vis));//每次找增廣路的時候清空visans += dfs(i);}}return ans; }int main() {//輸入匹配的兩個點集合的數量cin >> n >> m;//輸入兩個點集合成員間的匹配可能int x, y;for (int i = 0; i < m; i++){cin >> x >> y;Map[x][y] = 1;}//執行匈牙利算法,輸出最大匹配cout << maxmatch() << endl;return 0; }總結
以上是生活随笔為你收集整理的二分图匹配--匈牙利算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 百度首页新版功能介绍
- 下一篇: 【每日一题】7月10日精讲—矩阵取数游戏