On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertically, to an adjacent point. For each little man, you need to pay a $1 travel fee for every step he moves, until he enters a house. The task is complicated with the restriction that each house can accommodate only one little man.

Your task is to compute the minimum amount of money you need to pay in order to send these n little men into those n different houses. The input is a map of the scenario, a '.' means an empty space, an 'H' represents a house on that point, and am 'm' indicates there is a little man on that point. 

You can think of each point on the grid map as a quite large square, so it can hold n little men at the same time; also, it is okay if a little man steps on a grid with a house without entering that house.

Input

There are one or more test cases in the input. Each case starts with a line giving two integers N and M, where N is the number of rows of the map, and M is the number of columns. The rest of the input will be N lines describing the map. You may assume both N and M are between 2 and 100, inclusive. There will be the same number of 'H's and 'm's on the map; and there will be at most 100 houses. Input will terminate with 0 0 for N and M.

Output

For each test case, output one line with the single integer, which is the minimum amount, in dollars, you need to pay.

Sample Input

2 2
.m
H.
5 5
HH..m
.....
.....
.....
mm..H
7 8
...H....
...H....
...H....
mmmHmmmm
...H....
...H....
...H....
0 0

Sample Output

2
10
28 这个题目难在建图,就是把每一个人的位置,和每一个房子连起来,容量为1,费用为两个之间的距离。
然后就跑一个最小费用最大流就可以了。
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
#include <map>
#include <cstring>
#include <cmath>
#include <string>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = + ;
struct edge
{
int u, v, c, f, cost;
edge(int u, int v, int c, int f, int cost) :u(u), v(v), c(c), f(f), cost(cost) {}
};
vector<edge>e;
vector<int>G[maxn];
int a[maxn];//找增广路每个点的水流量
int p[maxn];//每次找增广路反向记录路径
int d[maxn];//SPFA算法的最短路
int inq[maxn];//SPFA算法是否在队列中
int s, t;
void init()
{
for (int i = ; i <= maxn; i++)G[i].clear();
e.clear();
}
void add(int u, int v, int c, int cost)
{
e.push_back(edge(u, v, c, , cost));
e.push_back(edge(v, u, , , -cost));
int m = e.size();
G[u].push_back(m - );
G[v].push_back(m - );
}
bool bellman(int s, int t, int& flow, long long & cost)
{
memset(d, inf, sizeof(d));
memset(inq, , sizeof(inq));
d[s] = ; inq[s] = ;//源点s的距离设为0,标记入队
p[s] = ; a[s] = INF;//源点流量为INF(和之前的最大流算法是一样的) queue<int>q;//Bellman算法和增广路算法同步进行,沿着最短路拓展增广路,得出的解一定是最小费用最大流
q.push(s);
while (!q.empty())
{
int u = q.front();
q.pop();
inq[u] = ;//入队列标记删除
for (int i = ; i < G[u].size(); i++)
{
edge & now = e[G[u][i]];
int v = now.v;
if (now.c > now.f && d[v] > d[u] + now.cost)
//now.c > now.f表示这条路还未流满(和最大流一样)
//d[v] > d[u] + e.cost Bellman 算法中边的松弛
{
d[v] = d[u] + now.cost;//Bellman 算法边的松弛
p[v] = G[u][i];//反向记录边的编号
a[v] = min(a[u], now.c - now.f);//到达v点的水量取决于边剩余的容量和u点的水量
if (!inq[v]) { q.push(v); inq[v] = ; }//Bellman 算法入队
}
}
}
if (d[t] == INF)return false;//找不到增广路
flow += a[t];//最大流的值,此函数引用flow这个值,最后可以直接求出flow
cost += (long long)d[t] * (long long)a[t];//距离乘上到达汇点的流量就是费用
for (int u = t; u != s; u = e[p[u]].u)//逆向存边
{
e[p[u]].f += a[t];//正向边加上流量
e[p[u] ^ ].f -= a[t];//反向边减去流量 (和增广路算法一样)
}
return true;
}
int MincostMaxflow(int s, int t, long long & cost)
{
cost = ;
int flow = ;
while (bellman(s, t, flow, cost));//由于Bellman函数用的是引用,所以只要一直调用就可以求出flow和cost
return flow;//返回最大流,cost引用可以直接返回最小费用
}
struct node
{
int x, y;
node(int x=,int y=):x(x),y(y){}
};
node peo[], house[];
char mp[][];
int main()
{
int n, m;
while(cin>>n>>m)
{
init();
int cas = , tot = ;
if (n == && m == ) break;
for (int i = ; i <= n; i++)
{
cin >> mp[i] + ;
for(int j=;j<=m;j++)
{
if (mp[i][j] == 'm') peo[++cas] = node(i, j);
if (mp[i][j] == 'H') house[++tot] = node(i, j);
}
}
s = , t = cas + tot + ;
for (int i = ; i <= cas; i++) add(s, i, , );
for (int i = ; i <= tot; i++) add(cas + i, t, , );
for(int i=;i<=cas;i++)
{
for(int j=;j<=tot;j++)
{
int cost = abs(peo[i].x - house[j].x) + abs(peo[i].y - house[j].y);
add(i, j + cas, , cost);
}
}
ll cost = ;
int ans = MincostMaxflow(s, t, cost);
printf("%lld\n", cost);
}
return ;
}

D - Going Home POJ - 2195 网络流的更多相关文章

  1. POJ 2195 Going Home 最小费用最大流 尼玛,心累

    D - Going Home Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Subm ...

  2. poj 2195 二分图带权匹配+最小费用最大流

    题意:有一个矩阵,某些格有人,某些格有房子,每个人可以上下左右移动,问给每个人进一个房子,所有人需要走的距离之和最小是多少. 貌似以前见过很多这样类似的题,都不会,现在知道是用KM算法做了 KM算法目 ...

  3. POJ 2195 Going Home / HDU 1533(最小费用最大流模板)

    题目大意: 有一个最大是100 * 100 的网格图,上面有 s 个 房子和人,人每移动一个格子花费1的代价,求最小代价让所有的人都进入一个房子.每个房子只能进入一个人. 算法讨论: 注意是KM 和 ...

  4. POJ 2195 Going Home (带权二分图匹配)

    POJ 2195 Going Home (带权二分图匹配) Description On a grid map there are n little men and n houses. In each ...

  5. poj 2195 Going Home(最小费最大流)

    poj 2195 Going Home Description On a grid map there are n little men and n houses. In each unit time ...

  6. 【POJ 2195】 Going Home(KM算法求最小权匹配)

    [POJ 2195] Going Home(KM算法求最小权匹配) Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submiss ...

  7. (网络流 匹配 KM) Going Home --poj -- 2195

    链接: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82835#problem/D 有n个人有n栋房子,每栋房子里能进一个人,但每走一格 ...

  8. kuangbin专题专题十一 网络流 Going Home POJ - 2195

    题目链接:https://vjudge.net/problem/POJ-2195 思路:曼哈顿距离来求每个人到每个房间的距离,把距离当作费用. 就可以用最小费用最大流来解决了,把每个房子拆成两个点,限 ...

  9. 图论--网络流--费用流POJ 2195 Going Home

    Description On a grid map there are n little men and n houses. In each unit time, every little man c ...

随机推荐

  1. Oracle RAC集群搭建(二)-基础环境配置

    01,创建用户,用户组 [root@rac1 ~]# groupadd -g 501 oinstall [root@rac1 ~]# groupadd -g 502 dba [root@rac1 ~] ...

  2. Java基础23-main方法

    /* 主函数(主方法) 1.public(访问修饰符,公共的)代表类或者该函数访问权限是最大的 2.static 代表主函数随着类的加载就已经存在了 3.void 代表主函数没有具体的返回值 4.ma ...

  3. innosetup区分正常状态和静默安装状态(通过传递的参数)

    命令行运行程序,如: myprogram.exe  /abc  /bcd 如果我们想获取其中的参数,“/abc”.“/bcd” 1. 直接使用innosetup自带的方法, GetCmdTail() ...

  4. 解决VMWARE 虚拟机安装64位系统“此主机支持 Intel VT-x,但 Intel VT-x 处于禁用状态

    VMWARE WORKSTATION 在安装64为操作系统报错,报错内容如图: 错误提示已经很清楚了,需要在BIOS 中打开intel VT-x g功能,开启此功能的前提是: 1.首先要确定的就是你的 ...

  5. 转帖:kindeditor编辑区空格被隐藏,导致所见所得不一致的解决办法

    1.修改kindereditor-all.js中的 var re = /(\s)<(/)?([\w-:]+)((?:\s+|(?:\s+[\w-:]+)|(?:\s+[\w-:]+=[^\s&q ...

  6. MySql存储引擎MyISAM和InnoDB的区别

    1.MySQL默认采用的是MyISAM. 2.MyISAM不支持事务,而InnoDB支持.InnoDB的AUTOCOMMIT默认是打开的,即每条SQL语句会默认被封装成一个事务,自动提交,这样会影响速 ...

  7. 安装 VS 2015 Update 2 + Windows SDK Tools 1.3.1 + Windows SDK 10586.212 后提示找不到 10586.0 SDK 问题的解决方法

    将 Visual Studio 2015 升级到 Update 2,并安装 Windows SDK Tools 1.3.1 和 Windows SDK 10586.212 后,有可能造成原本已安装的 ...

  8. node.js分片上传文件

    前端 : <html> <head> <title>分片上传文件</title> </head> <body> <div ...

  9. uiautomator 1使用简介

    1.生成build.xml android create uitest-project -n jar_name  -t id -p projectPah 2.修改build.xml 改成默认执行 bu ...

  10. 02.for循环

    语法: for(表达式1;表达式2;表达式3) { 循环体; } 练习1: namespace _02.for循环的练习01 { class Program { static void Main(st ...