日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

二分图完全匹配算法之匈牙利算法

發布時間:2024/8/1 编程问答 54 豆豆
生活随笔 收集整理的這篇文章主要介紹了 二分图完全匹配算法之匈牙利算法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近在參加了一個小項目,里面用到二分圖匹配算法,因為之前并沒有接觸過相關算法,于是找到一些博客進行了一番學習,但學習之后,發現部分博客或多或少存在一些另我疑惑的地方,于是,我打算寫此博客以鞏固對算法的理解。

一、二分圖基本概念

二分圖(Bipartite graph)又稱作二部圖,是圖論中的一種特殊模型。 設G=(V,E)是一個無向圖,如果頂點V可分割為兩個互不相交的子集(A,B),并且圖中的每條邊(i,j)所關聯的兩個頂點i和j分別屬于這兩個不同的頂點集(i in A,j in B),則稱圖G為一個二分圖。

通俗一點,二分圖是一類特殊的圖,它可以被劃分為兩個部分,每個部分內的點互不相連。

如下圖所示,可以將【2】【4】結點視為一個集合,【1】【3】【5】【6】結點視為一個集合,集合內部的結點互不相連,因此該圖為一個二分圖。

重要定理:G為二分圖的充要條件是G中的每一個圈的長度都是偶數。

二、二分圖匹配相關概念

1、什么是匹配?

注意,本文只討論二分圖的最大匹配,不討論最優匹配。

給定一個二分圖G=(V,E),在G的一個子圖M中,M的邊集{E}中的任意兩條邊都不依附于同一個頂點,則稱M是一個匹配;具有邊數量最多的匹配稱為最大匹配;若|V|=2|M|,則稱M為完美匹配

如下所示為一個二分圖的完美匹配:

二分圖完美匹配一定是最大匹配,最大匹配不一定是完美匹配。

2、什么是交替路與增廣路?

交替路:從一個未匹配點出發,依次經過非匹配邊、匹配邊、非匹配邊…形成的路徑叫交替路。

增廣路(Augmenting Path):從一個未匹配點出發,走交替路,如果途徑另一個未匹配點(出發點不算),則這條【交替路】稱為增廣路。

增廣路的三個性質:

  • M為G的最大匹配當且僅當不存在M的增廣路徑。
  • 增廣路P的路徑長度必定為奇數,第一條邊和最后一條邊都不屬于M,不匹配的邊比匹配的邊多一。
  • 不斷尋找增廣路可以得到一個更大的匹配M’,直到找不到更多的增廣路。
  • 增廣路的這三個性質可以用來尋找匹配,在接下來會說明。

    如下圖所示:

    路徑2->A->1->B為一條交替路,因為出發點2和途徑點B均為未匹配點,因此該路徑也為增廣路。

    三、匈牙利算法

    1、基本概念

    匈牙利算法的核心就是尋找增廣路。具體而言,匈牙利算法從二分圖中沒有匹配的點開始尋找增廣路徑(增廣路徑性質3)。找到增廣路后,根據增廣路徑的性質,顯然路徑里沒被匹配的連線比已經匹配了的連線多一條(增廣路徑性質2),于是對增廣路徑中的邊進行取反操作,這樣匹配數就比原來多1個。不斷執行上述操作,直到找不到增廣路徑為止,無法找到增廣路徑說明已達到最大匹配(增廣路徑性質1)。

    取反操作:將增廣路的匹配邊變成不匹配邊,不匹配邊變成匹配邊。

    如上圖所示:

  • 首先從未匹配點1開始尋找增廣路,找到了另一個未匹配點A說明找到了增廣路,停止尋找,進行取反操作,將非匹配邊變為匹配邊,于是1-A為匹配邊。
  • 從未匹配點2開始尋找增廣路,顯然2->A->1->B為增廣路,進行取反,于是此時匹配邊為2-A、1-B。
  • 從未匹配點3開始尋找增廣路,顯然3->A->2->C為增廣路,進行取反,于是匹配邊變為3-A、2-C、1-B。因為已經不存在未匹配點,此時已經找不到更多增廣路徑,因此達到了此二分圖的最大匹配。
  • 注:顯然,二分圖匹配結果并不唯一。

    以上就是匈牙利算法的過程,很明顯,搜尋增廣路徑這個步驟是基于深度優先搜索的。

    匈牙利算法尋找增廣路的偽代碼描述:

    //以下為尋找增廣路并進行取反操作的偽代碼,取反操作通過遞歸調用完成。 while(找到Xi的關聯頂點Yj){if(頂點Yj不在增廣路徑上){Yj加入增廣路;//如果Yj是未匹配點說明成功找到增廣路,從“Yj處繼續尋找能夠找到增廣路”屬于遞歸調用本函數過程,進行取反操作if(Yj是未匹配點||Yj處繼續尋找能夠找到增廣路){Yj的匹配點改為Xi;return true;}}return false; }

    2、匈牙利算法的實現

    網上搜索匈牙利算法,從思想上看都是基于dfs的,另外,我注意到也有一些博客提出了基于廣度優先(bfs)的匈牙利算法,我不確定所謂“基于bfs的匈牙利算法”能否稱為匈牙利算法,我個人的理解是匈牙利算法就是基于dfs的來尋找增廣路徑而實現的。

    2.1、實際問題

    問題描述

    RPG girls今天和大家一起去游樂場玩,終于可以坐上夢寐以求的過山車了。可是,過山車的每一排只有兩個座位,而且還有條不成文的規矩,就是每個女生必須找個個男生做partner和她同坐。但是,每個女孩都有各自的想法,舉個例子把,Rabbit只愿意和XHD或PQK做partner,Grass只愿意和linle或LL做partner,PrincessSnow愿意和水域浪子或偽酷兒做partner。考慮到經費問題,boss劉決定只讓找到partner的人去坐過山車,其他的人,嘿嘿,就站在下面看著吧。聰明的Acmer,你可以幫忙算算最多有多少對組合可以坐上過山車嗎?

    輸入

    輸入數據的第一行是三個整數K , M , N,分別表示可能的組合數目,女生的人數,男生的人數。0<K<=1000

    1<=N 和M<=500.接下來的K行,每行有兩個數,分別表示女生Ai愿意和男生Bj做partner。最后一個0結束輸入。

    輸出:對于每組數據,輸出一個整數,表示可以坐上過山車的最多組合數。

    樣例輸入:6 3 3 1 1 1 2 1 3 2 1 2 3 3 1 0

    樣例輸出:3

    這道題本質上就是求二分圖的最大匹配問題。

    2.2、代碼實現

    Java實現

    此代碼轉載自https://wmathor.com/index.php/archives/1344/,//***//表示是我添加的注釋。

    import java.util.Arrays; import java.util.Scanner;public class Main {static int[][] map;static int n, m;public static void main(String[] args) {Scanner cin = new Scanner(System.in);while (cin.hasNext()) {int t = cin.nextInt();if (t == 0)break;n = cin.nextInt();m = cin.nextInt();map = new int[n + 1][m + 1];for (int i = 0; i < t; i++)map[cin.nextInt()][cin.nextInt()] = 1; // 有向邊int count = 0; // 最大匹配數int[] mc = new int[m + 1]; // mc[i] = j 表示i號男生所連的女生是j號Arrays.fill(mc, -1); // 初始時所有女生都沒有連//***//以下for循環是核心部分,表示依次從未匹配點開始尋找增廣路徑for (int i = 1; i <= n; i++) {//***//將增廣路徑中的結點記錄下來,以免重復,因此每一次循環都必須重置。boolean[] vis = new boolean[m + 1]; // vis[i] = true 表示i號男生已經被匹配了//***//根據增廣路徑性質2、3,每找到一條增廣路徑就說明找到了一條匹配邊if (dfs(i, vis, mc))count++;}System.out.println(count);}}//***//注:這個是尋找增廣路徑的代碼,可以結合之前的偽代碼,每找到一條增廣路徑就說明找到了一條匹配邊。private static boolean dfs(int start, boolean[] vis, int[] mc) {for (int i = 1; i <= m; i++) { // 枚舉男生集if (!vis[i] && map[start][i] == 1) { // 如果這個男生沒被匹配并且和當前的start有邊相連vis[i] = true; // 將這個男生標記為匹配過//***//以下判斷語句中dfs遞歸調用,對應匈牙利算法中尋找增廣路徑并取反的操作,大家可以試著手動推理一下if (mc[i] == -1 || dfs(mc[i], vis, mc)) { // 這個男生沒有和女生匹配 || 這個男生所連的女生還有別的選擇,就把這個男生"騰"出來mc[i] = start;return true;}}}return false;} }

    Go:

    有時間再把go的代碼實現并添加過來,先畫個餅。

    四、總結

    匈牙利算法的核心在于找增廣路徑,注意增廣路徑的三個性質。文中偽代碼部分可以當成是解決這類問題的模板。

    本文內容也是我自己對于算法的理解,可能存在錯誤,歡迎批評指正。

    五、參考博客

    https://blog.csdn.net/lemonxiaoxiao/article/details/108672039

    https://zhuanlan.zhihu.com/p/208596378

    https://www.cxyxiaowu.com/874.html

    總結

    以上是生活随笔為你收集整理的二分图完全匹配算法之匈牙利算法的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。