您的位置:首页 > 其它

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算法模板

代码:

#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];
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: