KM算法(完备匹配下的最大权匹配)
2016-10-24 09:22
197 查看
KM算法求的是完备匹配下的最大权匹配: 在一个二分图内,左顶点为X,右顶点为Y,现对于每组左右连接XiYj有权wij,求一种匹配使得所有wij的和最大。
题目:http://acm.hdu.edu.cn/showproblem.php?pid=2255
题意:分房子,对于n个人对n所房子有自己的最大承受价格,要求每个人分到一所房子,并且要求收入最大
输入说明:输入n,代表n个人和n所房子,接下来n行n列代表第i个人对第j所房子的价格
题解:KM算法模板
代码:
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1533
题意:给定n*m的图,其中‘m’代表一个人,‘H’代表一个房子,要求移动最小的步数可以让所有人都进房子
输入说明:输入 n m,接下来是n*m的图
题解:KM算法模板题
代码:
KM算法模板
题目:http://acm.hdu.edu.cn/showproblem.php?pid=2255
题意:分房子,对于n个人对n所房子有自己的最大承受价格,要求每个人分到一所房子,并且要求收入最大
输入说明:输入n,代表n个人和n所房子,接下来n行n列代表第i个人对第j所房子的价格
题解:KM算法模板
代码:
#include <stdio.h> #include <string.h> #define M 310 #define inf 0x3f3f3f3f int n,nx,ny; int match[M],lx[M],ly[M],slack[M]; int visx[M],visy[M],mp[M][M]; int DFS(int root) { visx[root] = 1; for (int son = 1;son <= ny;son ++) { if (visy[son]) continue; int gap = lx[root] + ly[son] - mp[root][son]; if (gap == 0) { visy[son] = 1; if (match[son] == -1||DFS(match[son])) { match[son] = root; return true; } } else if (slack[son] > gap) slack[son] = gap; } return 0; } int KM() { int i,j; memset (match,-1,sizeof(match)); memset (ly,0,sizeof(ly)); for (i = 1;i <= nx;i ++) //lx初始化为与它关联边中最大的 for (j = 1,lx[i] = -inf;j <= ny;j ++) if (mp[i][j] > lx[i]) lx[i] = mp[i][j]; for (int x = 1;x <= nx;x ++) { for (i = 1;i <= ny;i ++) slack[i] = inf; while (1) { memset (visx,0,sizeof(visx)); memset (visy,0,sizeof(visy)); if (DFS(x)) break; int d = inf; for (i = 1;i <= ny;i ++) if (!visy[i]&&d > slack[i]) d = slack[i]; for (i = 1;i <= nx;i ++) if (visx[i]) lx[i] -= d; for (i = 1;i <= ny;i ++) if (visy[i]) ly[i] += d; else slack[i] -= d; } } int res = 0; for (i = 1;i <= ny;i ++) if (match[i] > -1) res += mp[match[i]][i]; return res; } int main () { int i,j; while (scanf ("%d",&n)!=EOF) { nx = ny = n; for (i = 1;i <= n;i ++) for (j = 1;j <= n;j ++) {scanf ("%d",&mp[i][j]);} int ans = KM(); printf ("%d\n",ans); } return 0; }
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1533
题意:给定n*m的图,其中‘m’代表一个人,‘H’代表一个房子,要求移动最小的步数可以让所有人都进房子
输入说明:输入 n m,接下来是n*m的图
题解:KM算法模板题
代码:
#include<iostream> #include <stdio.h> #include <string.h> #include<vector> #include<utility> #include<cmath> #define M 310 #define inf 0x3f3f3f3f using namespace std; char c[150][150]; vector<pair<int,int> > house; vector<pair<int,int> > people; int nx,ny; int match[M],lx[M],ly[M],slack[M]; int visx[M],visy[M],mp[M][M]; int DFS(int root) { visx[root] = 1; for (int son = 1;son <= ny;son ++) { if (visy[son]) continue; int gap = lx[root] + ly[son] - mp[root][son]; if (gap == 0) { visy[son] = 1; if (match[son] == -1||DFS(match[son])) { match[son] = root; return true; } } else if (slack[son] > gap) slack[son] = gap; } return 0; } int KM() { int i,j; memset (match,-1,sizeof(match)); memset (ly,0,sizeof(ly)); for (i = 1;i <= nx;i ++) //lx初始化为与它关联边中最大的 for (j = 1,lx[i] = -inf;j <= ny;j ++) if (mp[i][j] > lx[i]) lx[i] = mp[i][j]; for (int x = 1;x <= nx;x ++) { for (i = 1;i <= ny;i ++) slack[i] = inf; while (1) { memset (visx,0,sizeof(visx)); memset (visy,0,sizeof(visy)); if (DFS(x)) break; int d = inf; for (i = 1;i <= ny;i ++) if (!visy[i]&&d > slack[i]) d = slack[i]; for (i = 1;i <= nx;i ++) if (visx[i]) lx[i] -= d; for (i = 1;i <= ny;i ++) if (visy[i]) ly[i] += d; else slack[i] -= d; } } int res = 0; for (i = 1;i <= ny;i ++) if (match[i] > -1) res += mp[match[i]][i]; return -res; } int main () { int i,j; int n,m; while (~scanf ("%d %d",&n,&m) && n+m!=0) { for (i = 1;i <= n;i ++) { getchar(); for(j=1;j <= m;j++) { scanf("%c",&c[i][j]); if(c[i][j]=='H') house.push_back(make_pair(i,j)); else if(c[i][j]=='m') people.push_back(make_pair(i,j)); } } nx=people.size(); ny=house.size(); for(i=0;i<nx;i++) { for(j=0;j<ny;j++) { mp[i+1][j+1]=-(fabs(people[i].first-house[j].first)+fabs(people[i].second-house[j].second)); } } house.clear();people.clear(); int ans = KM(); printf ("%d\n",ans); } return 0; }
KM算法模板
#define M 310 #define inf 0x3f3f3f3f //以下是最大权匹配 int nx,ny;//nx代表匹配左项的多少,ny表示匹配右项的多少 int match[M],lx[M],ly[M],slack[M];//match[右项]=所对应的左项 int visx[M],visy[M],mp[M][M]; int DFS(int root) { visx[root] = 1; for (int son = 1;son <= ny;son ++) { if (visy[son]) continue; int gap = lx[root] + ly[son] - mp[root][son]; if (gap == 0) { visy[son] = 1; if (match[son] == -1||DFS(match[son])) { match[son] = root; return true; } } else if (slack[son] > gap) slack[son] = gap; } return 0; } int KM() { int i,j; memset (match,-1,sizeof(match)); memset (ly,0,sizeof(ly)); for (i = 1;i <= nx;i ++) //lx初始化为与它关联边中最大的 for (j = 1,lx[i] = -inf;j <= ny;j ++) if (mp[i][j] > lx[i]) lx[i] = mp[i][j]; for (int x = 1;x <= nx;x ++) { for (i = 1;i <= ny;i ++) slack[i] = inf; while (1) { memset (visx,0,sizeof(visx)); memset (visy,0,sizeof(visy)); if (DFS(x)) break; int d = inf; for (i = 1;i <= ny;i ++) if (!visy[i]&&d > slack[i]) d = slack[i]; for (i = 1;i <= nx;i ++) if (visx[i]) lx[i] -= d; for (i = 1;i <= ny;i ++) if (visy[i]) ly[i] += d; else slack[i] -= d; } } int res = 0; for (i = 1;i <= ny;i ++) if (match[i] > -1) res += mp[match[i]][i]; return res;//求最小权时取-res,同时图mp[i][j]=-mp[i][j]; }
相关文章推荐
- KM算法(二分图完备匹配下的最大权匹配)
- 完备匹配下的最大权匹配-KM算法的一般模板
- hdu 2255 带权最大匹配 km算法
- POJ-2195 Going Home (最小费用最大流初学 && 最大权二分匹配—KM算法)
- km算法(求二分图带权的最大匹配)
- 【模板】KM算法模板(带注释)——二分图带权最大匹配
- 求最大权二分匹配的KM算法
- 理论: 图论(11): 二分图的最大权匹配(KM算法)HDU 2255
- HDU-2255 奔小康赚大钱(完备匹配下的最大权匹配) 解题报告
- 模板_HDU2255奔小康赚大钱_最大权最大匹配问题_KM算法
- 【二分图最大权匹配】【KM算法模板】
- HDU-2255 奔小康赚大钱(完备匹配下的最大权匹配) 解题报告
- 二分图最大权匹配(KM算法)
- uoj #80. 二分图最大权匹配 KM算法
- 二分图 最大权匹配 km算法
- POJ - 2195 Going Home (构图 最大匹配KM算法)
- poj 2195 KM算法(完备匹配)
- HDU3488 Tour(二分图最小完备匹配,KM算法,转化思想)
- HDU-2255 奔小康赚大钱(完备匹配下的最大权匹配) 解题报告
- KM算法求完全匹配情况下的最大匹配