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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

二分图匹配问题

發布時間:2024/4/18 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 二分图匹配问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最大匹配

N對人兩兩之間存在關系,求最多的匹配

  • 最小點覆蓋=最大匹配
  • 最大獨立集=頂點數-最大匹配
  • 最小路徑覆蓋=頂點數-最大匹配
    匈牙利算法:時間O(n3,nm{n^3}, {nm}n3nm),空間O(n2,n+m{n^2,n+m}n2n+m)
int g[maxn][maxn]; // 記錄兩個人的關系 int girl[maxn], used[maxn]; // girl記錄已經確定的關系 // used 記錄每次增廣路上右邊的點 int find (int x) {for (int i = 1; i <= n; ++i) {// 對于X遍歷右邊的點,如果X與i存在關系而且i在本輪還沒有確定關系,那么X和i就有可能匹配,先標記下if (g[x][i] && used[i] == 0) {used[i] = 1;// 如果i沒有被匹配 or i已經被前面的點匹配過了而且之前的人還能找到其他人匹配,X就和i可以正式確定關系if (!girl[i] || find(girl[i])) {girl[i] = x;return true;}}}return false; } for (int i = 1; i <= n; ++i) {mem(used, 0);ans += find(i); }

最佳匹配

最佳匹配是完備匹配,每個人都要被匹配。在完備匹配的基礎上求一種權值最大的匹配

  • KM算法:設置兩個頂標(左邊頂點賦值為對應邊的最大權值,右邊賦值為0)先按照最大的權值選邊(匈牙利算法),選邊沖突時計算增廣路上最小的降低費用,更新每個點(增廣路上左邊的點減去費用,右邊的點加上費用)這樣保證增廣路可以繼續找到解而且之前連接的邊也存在,這樣遍歷每個點即可。
  • 如果求權值和最小的最佳匹配,存負邊即可。
  • 如果不是完全圖,計算的時候可以將沒有給出的邊賦值為**-inf**這樣不會影響答案,統計答案的時候判定一下即可。
int n; int usex[maxn], usey[maxn], topx[maxn], topy[maxn], slack[maxn]; int girl[maxn], g[maxn][maxn]; // usex, usey 用在每次的匈牙利算法記錄增廣路上的點,方便后面調整頂標的權值 // girl 記錄已經確定的關系 // topx, topy記錄左右的頂標 int dfs(int x) {usex[x] = 1; // 增光路左邊的點for (int i = 1; i <= n; ++i) {if (usey[i]) continue;int tmp = topx[x] + topy[i] - g[x][i]; if (tmp != 0) { // tmp = 0,邊有效slack[i] = min(tmp, slack[i]); // 記錄最小降低值}else {usey[i] = 1; // 增光路右邊的點if (girl[i] == -1 || dfs(girl[i])) {girl[i] = x;return 1;}}}return 0; } int km() {memset(girl, -1, sizeof(girl));memset(topx, 0, sizeof(topx));memset(topy, 0, sizeof(topy));// 更新topx為最大值for (int i = 1; i <= n; ++i) {for (int j = 1; j <= n; ++j) {topx[i] = max(topx[i], g[i][j]);}}for (int i = 1; i <= n; ++i) {memset(slack, inf, sizeof(slack));while (1) {memset(usex, 0, sizeof(usex));memset(usey, 0, sizeof(usey));if (dfs(i)) break;int tmp = inf;// 取最小的降低值for (int j = 1; j <= n; ++j) {if (usey[j]) continue;tmp = min(tmp, slack[j]);}if (tmp == inf) return -1;// 更新左頂標for (int j = 1; j <= n; ++j) {if (usex[j]) topx[j] -= tmp;}// 更新右頂標for (int j = 1; j <= n; ++j) {if (usey[j]) topy[j] += tmp;else slack[j] -= tmp;}}}int ans = 0;for (int i = 1; i <= n; ++i) {if (girl[i] != -1) ans += g[girl[i]][i];}return ans; }

總結

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

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