您的位置:首页 > 编程语言 > Go语言

pku 2195 Going Home KM最小权匹配问题

2012-07-21 20:58 260 查看
http://poj.org/problem?id=2195

在一个n*m的方格里有nx人(m)和ny个房子(H),(nx = ny)人每次可以向四周移动单位距离,花费1¥,求最小花费是每个人都能进入一个房间。

最小费用最大流可以做/article/7104890.html

这里是个二分图求最小权匹配问题,可以用KM算法求,只要把w[i][j] 化成负数,太用木板求最大的负数,然后输出-KM()就得到最小的整数了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#define maxn 102
using namespace std;

struct node
{
int x,y;
}p[maxn*50],h[maxn*50];
const int inf = 99999999;
int w[maxn][maxn],link[maxn];
int lx[maxn],ly[maxn];//记录顶标
int slack[maxn];
bool vtx[maxn],vty[maxn];//记录X,Y点集是否被访问过
int nx,ny,n,m;
char str[maxn][maxn];

bool dfs(int i)
{
int j;
vtx[i] = true;
for (j = 0; j < ny; ++j)
{
if (vty[j]) continue;
int tmp = lx[i] + ly[j] - w[i][j];
if (tmp == 0)
{
vty[j] = true;
if (link[j] == -1 || dfs(link[j]))
{
link[j] = i;
return true;
}
}
else
slack[j] = min(tmp,slack[j]);
}
return false;
}
int KM()
{
int i,j;
for (i = 0; i < nx; ++i)
{
for (j = 0,lx[i] = -inf; j < ny; ++j)
{
lx[i] = max(lx[i],w[i][j]);
}
}
for (i = 0; i < maxn; ++i)
{
link[i] = -1; ly[i] = 0;
}
for (i = 0; i < nx; ++i)
{
for (j = 0; j < ny; ++j) slack[j] = inf;
while (1)
{
for (j = 0; j < maxn; ++j) vtx[j] = vty[j] = false;
if (dfs(i)) break;
int d = inf;
for (j = 0; j < ny; ++j)
{
if (!vty[j] && d > slack[j])
d = slack[j];
}
if (d == inf) return -1;
for (j = 0; j < nx; ++j)
if (vtx[j]) lx[j] -= d;
for (j = 0; j < ny; ++j)
if (vty[j]) ly[j] += d;
else slack[j] -= d;
}
}
int sum = 0;
for (i = 0; i < ny; ++i)
{
if (link[i] > -1) sum += w[link[i]][i];
}
return sum;
}
int main()
{
int i,j;
while (~scanf("%d%d",&n,&m))
{
if (!n && !m) break;
nx = ny = 0;
for (i = 0; i < n; ++i)
{
scanf("%s",str[i]);
for (j = 0; j < m; ++j)
{
if (str[i][j] == 'm')
{
p[nx].x = i; p[nx++].y = j;
}
else if (str[i][j] == 'H')
{
h[ny].x = i; h[ny++].y = j;
}
}
}
for (i = 0; i < nx; ++i)
{
for (j = 0; j < ny; ++j)
{
w[i][j] = -inf;
}
}
for (i = 0; i < nx; ++i)
{
for (j = 0; j < ny; ++j)
{
w[i][j] = -(abs(p[i].x - h[j].x) + abs(p[i].y - h[j].y));
}
}

printf("%d\n",-KM());
}
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: