帶權值的二分圖匹配 KM演算法

來源:互聯網
上載者:User

1,如果二分圖不是完全二分圖,我們通過添加無用路徑(最大匹配中,路徑權值為0)和頂點使之成為完全二分圖;

2,使用KM演算法求解,KM演算法核心需要理解feasible vertex labeling和equality subgraph概念,在equality subgraph中尋找最大匹配(採用匈牙利演算法),如果最大匹配正好為完全符合,根據KM理論,這個完全符合就是帶權值的最大匹配;如果在當前的equality subgraph擷取的最大匹配不是完全符合,我們通過KM演算法中提供的修改label方法,增加新的y點,得到新的equality subgraph,再繼續在新的subgraph尋找最大匹配,如此迴圈。

代碼如下:

#include <cstdio>#include <memory.h>#include <algorithm>    // 使用其中的 min 函數using namespace std;const int MAX = 1024;int n; // X 的大小int weight[MAX][MAX]; // X 到 Y 的映射(權重)int lx[MAX], ly[MAX]; // 標號bool sx[MAX], sy[MAX]; // 是否被搜尋過int match[MAX]; // Y(i) 與 X(match [i]) 匹配// 初始化權重void init(int size);// 從 X(u) 尋找增廣道路,找到則返回 truebool path(int u);// 參數 maxsum 為 true ,返回最大權匹配,否則最小權匹配int bestmatch(bool maxsum = true);void init(int size){// 根據實際情況,添加代碼以初始化n = size;for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)scanf("%d", &weight[i][j]);}/* * 和二分圖的思路類似,在子圖中尋找增廣路徑 */bool path(int u){sx[u] = true;for (int v = 0; v < n; v++)if (!sy[v] && lx[u] + ly[v] == weight[u][v]){sy[v] = true;if (match[v] == -1 || path(match[v])){match[v] = u;return true;}}return false;}int bestmatch(bool maxsum){int i, j;if (!maxsum){for (i = 0; i < n; i++)for (j = 0; j < n; j++)weight[i][j] = -weight[i][j];}// 初始化標號for (i = 0; i < n; i++){lx[i] = -0x1FFFFFFF;ly[i] = 0;for (j = 0; j < n; j++)if (lx[i] < weight[i][j])lx[i] = weight[i][j];}memset(match, -1, sizeof(match));for (int u = 0; u < n; u++)while (1){memset(sx, 0, sizeof(sx));memset(sy, 0, sizeof(sy));if (path(u))//一直尋找增廣路徑,直到子圖中沒有增廣路徑,我們通過修改label來增加新的點,增加的點必為ybreak;// 修改標號int dx = 0x7FFFFFFF;for (i = 0; i < n; i++)if (sx[i])for (j = 0; j < n; j++)if (!sy[j])dx = min(lx[i] + ly[j] - weight[i][j], dx);//找到鬆弛變數最小的點for (i = 0; i < n; i++){if (sx[i])lx[i] -= dx;if (sy[i])ly[i] += dx;}}int sum = 0;for (i = 0; i < n; i++)sum += weight[match[i]][i];if (!maxsum){sum = -sum;for (i = 0; i < n; i++)for (j = 0; j < n; j++)weight[i][j] = -weight[i][j]; // 如果需要保持 weight [ ] [ ] 原來的值,這裡需要將其還原}return sum;}int main(){int n;scanf("%d", &n);init(n);int cost = bestmatch(true);printf("%d ", cost);for (int i = 0; i < n; i++){printf("Y %d -> X %d ", i, match[i]);}return 0;}

附帶poj2195解法:

/* * poj2195.cpp * *  Created on: 2012-5-9 *      Author: ict */#include <cstdio>#include <cstdlib>#include <string.h>#include <algorithm>#include <cmath>using namespace std;#define MAX 200typedef struct GRID{int x;int y;}grid, pgrid;grid M[MAX], H[MAX];int n; // X 的大小int weight[MAX][MAX]; // X 到 Y 的映射(權重)int lx[MAX], ly[MAX]; // 標號bool sx[MAX], sy[MAX]; // 是否被搜尋過int match[MAX]; // Y(i) 與 X(match [i]) 匹配/* * 和二分圖的思路類似,在子圖中尋找增廣路徑 */bool path(int u){sx[u] = true;for (int v = 0; v < n; v++)if (!sy[v] && lx[u] + ly[v] == weight[u][v]){sy[v] = true;if (match[v] == -1 || path(match[v])){match[v] = u;return true;}}return false;}int bestmatch(bool maxsum){int i, j;if (!maxsum){for (i = 0; i < n; i++)for (j = 0; j < n; j++)weight[i][j] = -weight[i][j];}// 初始化標號for (i = 0; i < n; i++){lx[i] = -0x1FFFFFFF;ly[i] = 0;for (j = 0; j < n; j++)if (lx[i] < weight[i][j])lx[i] = weight[i][j];}memset(match, -1, sizeof(match));for (int u = 0; u < n; u++)while (1){memset(sx, 0, sizeof(sx));memset(sy, 0, sizeof(sy));if (path(u))//一直尋找增廣路徑,直到子圖中沒有增廣路徑,我們通過修改label來增加新的點,增加的點必為ybreak;// 修改標號int dx = 0x7FFFFFFF;for (i = 0; i < n; i++)if (sx[i])for (j = 0; j < n; j++)if (!sy[j])dx = min(lx[i] + ly[j] - weight[i][j], dx);//找到鬆弛變數最小的點for (i = 0; i < n; i++){if (sx[i])lx[i] -= dx;if (sy[i])ly[i] += dx;}}int sum = 0;for (i = 0; i < n; i++)sum += weight[match[i]][i];if (!maxsum){sum = -sum;for (i = 0; i < n; i++)for (j = 0; j < n; j++)weight[i][j] = -weight[i][j]; // 如果需要保持 weight [ ] [ ] 原來的值,這裡需要將其還原}return sum;}int main(){int row, col;int i, j;int ch;int mCount, hCount;while(1){scanf("%d %d", &row, &col);getchar();if(row == 0 && col == 0)break;mCount = 0;hCount = 0;for(i = 0; i < row ; i++){for(j = 0; j < col; j++){ch = getchar();if(ch == 'm'){M[mCount].x = i;M[mCount].y = j;mCount++;}elseif(ch == 'H'){H[hCount].x = i;H[hCount].y = j;hCount++;}}getchar();}n = mCount;for(i = 0 ; i < n; i++)for(j = 0; j < n; j++){weight[i][j] = abs(M[i].x - H[j].x) + abs(M[i].y - H[j].y);}printf("%d\n", bestmatch(false));}return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.