pku 2195 Going Home KM最小权匹配问题
http://poj.org/problem?id=2195
在一个n*m的方格里有nx人(m)和ny个房子(H),(nx = ny)人每次可以向四周移动单位距离,花费1¥,求最小花费是每个人都能进入一个房间。
最小费用最大流可以做http://www.cnblogs.com/E-star/archive/2012/06/28/2567079.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; }