#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//#define DEBUG
#ifdef DEBUG
#define debug(...) printf( __VA_ARGS__)
#else
#define debug(...)
#endif
#define N 101
#define MAX_INT 2000000
#define min(a, b) (a) < (b) ? (a) : (b)
#define max(a, b) (a) > (b) ? (a) : (b)
using namespace std;
int weight[N][N]; /* X集合点到Y集合点的权重 */
int lx[N], ly[N]; /* 标号 */
char visitx[N], visity[N]; /* 用于深度搜索,同时可以标记S和T集合的点 */
int mat[N]; /* mat[y] = x,表示集合Y的y点的匹配为x */
int slack[N]; /* slack[x]保存相对与顶点x的最小al,初始时为无穷大, dfs寻找增广路径的时候不断更新,并且会越来越小 */
int nx, ny;
struct position {
int x;
int y;
};
/* 从顶点x开始深度优先寻找增广路径, 寻找的过程中同时更新slack数组
* 和mat数组,若找到返回1
* 若找不到返回0,此时visitx[x] = 1的点属于S集合
* visity[y] = 1的点属于T集合
*/
int find(int x)
{
int y, t;
visitx[x] = 1;
debug("访问顶点X.%d\n", x);
for (y = 1; y <= ny; y++) {
if (!visity[y] && weight[x][y] != 0) {
t = lx[x] + ly[y] - weight[x][y];
if (t != 0) {
slack[x] = min(slack[x], t);
}
else {
visity[y] = 1;
debug("访问顶点Y.%d\n", y);
if ((mat[y] == -1 || find(mat[y]))) {
mat[y] = x;
return 1;
}
debug("否定顶点Y.%d\n", y);
}
}
}
return 0;
}
int main()
{
int x, y, s, min_al, cost, m, n;
char ch;
struct position man[N], home[N];
while (cin>>m>>n, m) {
//初始化l[v]
memset(weight, 0, sizeof(weight));
memset(ly, 0, sizeof(ly));
memset(mat, -1, sizeof(mat));
for (x = 1; x <= N; x++) {
lx[x] = -2000000;
slack[x] = MAX_INT;
}
//输入数据
nx = ny = 0;
for (x = 1; x <= m; x++) {
for (y = 1; y <= n; y++) {
cin >> ch;
if (ch == 'm') {
man[++nx].x = x;
man[nx].y = y;
}
else if (ch == 'H') {
home[++ny].x = x;
home[ny].y = y;
}
}
}
//建图
for (x = 1; x <= nx; x++) {
for (y = 1; y <= ny; y++) {
weight[x][y] = abs(man[x].x-home[y].x) + abs(man[x].y-home[y].y);
weight[x][y] *= -1; /* 题目要求最小权匹配,故把权值乘以-1,转变成求最大权匹配 */
lx[x] = max(lx[x], weight[x][y]); /* lx[x]初始化为最大权值 */
}
}
//给每个顶点寻找增广路径,若找不到就重新标号
for (s = 1; s <= nx;) {
for (;;) {
memset(visitx, 0, sizeof(visitx));
memset(visity, 0, sizeof(visity));
if (find(s)) {
s++;
debug("增广路径找到...\n");
break;
}
debug("从顶点%d找不到增广路径, 更新顶点标号...\n", s);
//在S集合中找最小的lx[x]+ly[y]-weight[x][y], 借助slack数组
min_al = MAX_INT;
for (x = 1; x <= nx; x++) {
if (visitx[x] && slack[x] < min_al) {
min_al = slack[x];
}
}
//更新S集合和T集合顶点标号
for (x = 1; x <= nx; x++) {
if (visitx[x]) lx[x] -= min_al;
}
for (y = 1; y <= ny; y++) {
if (visity[y]) ly[y] += min_al;
}
}
}
//打印匹配结果
for (y = 1; y <= ny; y++) {
if (mat[y] != -1) {
debug("X.%d-->Y.%d %d\n", mat[y], y, weight[mat[y]][y]);
}
}
//计算最大权
cost = 0;
for (x = 1; x <= nx; x++) {
cost += lx[x];
}
for (y = 1; y <= ny; y++) {
cost += ly[y];
}
printf("%d\n", -cost);
}
return 0;
}
分享到:
相关推荐
这是北京大学ACM也就是POJ2195的源代码,用的是最优匹配算法。
北大POJ2195-Going Home【费用流】 解题报告+AC代码 http://blog.csdn.net/lyy289065406/article/details/6732762
POJ各题算法分类和题目推荐 ACM必看 POJ各题算法分类和题目推荐 ACM必看 POJ各题算法分类和题目推荐 ACM必看
poj1087贪心算法实验报告 poj1087贪心算法实验报告
POJ中级图算法所有题目【解题报告+AC代码】 我的所有POJ解题报告 http://blog.csdn.net/lyy289065406/article/details/6642573
poj acm题解,包括绝大部分poj题目的题解,可以供acm爱好者学习研究
poj上的算法题目分类,对于大家想练习算法的同鞋可以参考一下,里面按类列出了各种算法的题号。
POJ各题算法分类和题目推荐.pdf
解决算法问题 poj1082, poj1150, poj1180, poj1201, poj1222,代码完成所给题目要求。
POJ题目分类,列出了所有的类目,里面写了一些很好的框架。
供初学编程基本算法的人练习使用,在poj.grids.cn上
北大POJ初级-图算法 解题报告+AC代码
北大POJ初级-基本算法 解题报告+AC代码
POJ上的一道题目,自己写的代码,因为想下载别人的, 所以就放上了。
关于C++ 算法 北大网站POJ 八数码问题
北大POJ中级-基本算法 解题报告+AC代码
用贪心算法解决POJ 1065的木棍处理问题
这里面有介绍ACM中的算法,包括算法分类,以及对应在POJ上面的训练题目
POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类
【二分图顶点覆盖->最小割->最大流->Dinic算法求解】 解题报告+AC代码 http://hi.csdn.net/!s/WKVPR0 ----> 我的所有POJ解题报告 http://blog.csdn.net/lyy289065406/article/details/6642573