Going Home
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 18169   Accepted: 9268

Description

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

Source

题意:给定一张N*M的图。当中‘.’为空地,小人能够走,‘m’为小人,‘H’为房子。小人能够路过。小人一次仅仅能沿着上下左右走一个格子。如今要求每一个小人都进入一个不同的房子。求小人走的步数最小数。

题解:这题能够看成最小费用流来解,当中小人到房子的距离为费用,容量为1。设置源点到每一个小人的容量为1。费用为0,每一个房子到汇点费用为0。容量为1,剩下的就是求最小费用流了。

版本号一:最小费用流:125ms

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <queue> const int maxn = 205;
const int inf = 0x3f3f3f3f;
char str[maxn];
int head[maxn], n, m; // n rows, m columns
struct Node {
int x, y;
} A[maxn], B[maxn];
int id1, id2, id, source, sink;
struct node {
int f, c, u, v, next;
} E[maxn * maxn];
bool vis[maxn];
int pre[maxn], dist[maxn]; void addEdge(int u, int v, int c, int f) {
E[id].u = u; E[id].v = v;
E[id].c = c; E[id].f = f;
E[id].next = head[u]; head[u] = id++; E[id].u = v; E[id].v = u;
E[id].c = 0; E[id].f = -f;
E[id].next = head[v]; head[v] = id++;
} void getMap() {
int i, j, dis; Node e;
id = id1 = id2 = 0;
for(i = 0; i < n; ++i) {
scanf("%s", str);
for(j = 0; str[j] != '\0'; ++j) {
if(str[j] == '.') continue;
e.x = i; e.y = j;
if(str[j] == 'm') A[id1++] = e;
else B[id2++] = e;
}
} memset(head, -1, sizeof(head));
source = id1 + id2; sink = source + 1;
for(i = 0; i < id1; ++i) {
for(j = 0; j < id2; ++j) {
dis = abs(A[i].x - B[j].x) + abs(A[i].y - B[j].y);
addEdge(i, id1 + j, 1, dis); // uvcf
}
addEdge(source, i, 1, 0);
}
for(j = 0; j < id2; ++j)
addEdge(id1 + j, sink, 1, 0);
} bool SPFA(int start, int end) {
std::queue<int> Q; int i, u, v;
memset(vis, 0, sizeof(vis));
memset(pre, -1, sizeof(pre));
memset(dist, 0x3f, sizeof(pre));
Q.push(start); vis[start] = 1; dist[start] = 0;
while(!Q.empty()) {
u = Q.front(); Q.pop();
vis[u] = 0;
for(i = head[u]; i != -1; i = E[i].next) {
v = E[i].v;
if(E[i].c && dist[v] > dist[u] + E[i].f) {
dist[v] = dist[u] + E[i].f;
pre[v] = i;
if(!vis[v]) {
Q.push(v); vis[v] = 1;
}
}
}
}
return dist[end] != inf;
} int Min_Cost_Flow(int start, int end) {
int ans_cost = 0, u, minCut;
while(SPFA(start, end)) {
minCut = inf;
for(u = pre[end]; u != -1; u = pre[E[u].u]) {
if(minCut > E[u].c) minCut = E[u].c;
}
for(u = pre[end]; u != -1; u = pre[E[u].u]) {
E[u].c -= minCut; E[u^1].c += minCut;
}
ans_cost += minCut * dist[end];
}
return ans_cost;
} void solve() {
printf("%d\n", Min_Cost_Flow(source, sink));
} int main() {
// freopen("stdin.txt", "r", stdin);
while(scanf("%d%d", &n, &m), n | m) {
getMap();
solve();
}
return 0;
}

版本号二:KM:0ms

#include <stdio.h>
#include <string.h>
#include <stdlib.h> const int maxn = 105;
const int largeNum = 210;
const int inf = 0x3f3f3f3f;
int n, m; // n rows, m columns
char str[maxn];
struct Node {
int x, y;
} A[maxn], B[maxn];
int id1, id2;
int G[maxn][maxn];
int Lx[maxn], Ly[maxn];
int match[maxn];
bool visx[maxn], visy[maxn];
int slack[maxn]; void getMap() {
int i, j, dis; Node e;
id1 = id2 = 0;
for(i = 0; i < n; ++i) {
scanf("%s", str);
for(j = 0; str[j] != '\0'; ++j) {
if(str[j] == '.') continue;
e.x = i; e.y = j;
if(str[j] == 'm') A[id1++] = e;
else B[id2++] = e;
}
}
memset(G, 0, sizeof(G));
for(i = 0; i < id1; ++i) {
for(j = 0; j < id2; ++j) {
G[i][j] = largeNum - (abs(A[i].x - B[j].x) + abs(A[i].y - B[j].y));
}
}
} bool DFS(int cur) {
int t, y;
visx[cur] = true;
for(y = 0; y < id2; ++y) {
if(visy[y]) continue;
t = Lx[cur] + Ly[y] - G[cur][y];
if(t == 0) {
visy[y] = true;
if(match[y] == -1 || DFS(match[y])) {
match[y] = cur; return true;
}
} else if(slack[y] > t) slack[y] = t;
}
return false;
} int KM() {
int i, j, x, d, ret;
memset(match, -1, sizeof(match));
memset(Ly, 0, sizeof(Ly));
for(i = 0; i < id1; ++i) {
Lx[i] = -inf;
for(j = 0; j < id2; ++j)
if(G[i][j] > Lx[i]) Lx[i] = G[i][j];
}
for(x = 0; x < id1; ++x) {
memset(slack, 0x3f, sizeof(slack));
while(true) {
memset(visx, 0, sizeof(visx));
memset(visy, 0, sizeof(visy));
if(DFS(x)) break;
d = inf;
for(i = 0; i < id2; ++i)
if(!visy[i] && d > slack[i])
d = slack[i];
for(i = 0; i < id1; ++i)
if(visx[i]) Lx[i] -= d;
for(i = 0; i < id2; ++i)
if(visy[i]) Ly[i] += d;
else slack[i] -= d;
}
}
ret = 0;
for(i = 0; i < id1; ++i)
if(match[i] > -1) ret += G[match[i]][i];
return ret;
} void solve() {
printf("%d\n", largeNum * id1 - KM());
} int main() {
// freopen("stdin.txt", "r", stdin);
while(scanf("%d%d", &n, &m), n | m) {
getMap();
solve();
}
return 0;
}

版权声明:本文博主原创文章,博客,未经同意不得转载。

POJ2195 Going Home 【最小费用流】+【最佳匹配图二部】的更多相关文章

  1. Luogu 1559 运动员最佳匹配问题(带权二分图最大匹配)

    Luogu 1559 运动员最佳匹配问题(带权二分图最大匹配) Description 羽毛球队有男女运动员各n人.给定2 个n×n矩阵P和Q.P[i][j]是男运动员i和女运动员j配对组成混合双打的 ...

  2. 二分图匹配之最佳匹配——KM算法

    今天也大致学了下KM算法,用于求二分图匹配的最佳匹配. 何为最佳?我们能用匈牙利算法对二分图进行最大匹配,但匹配的方式不唯一,如果我们假设每条边有权值,那么一定会存在一个最大权值的匹配情况,但对于KM ...

  3. opencv学习之路(34)、SIFT特征匹配(二)

    一.特征匹配简介 二.暴力匹配 1.nth_element筛选 #include "opencv2/opencv.hpp" #include <opencv2/nonfree ...

  4. KM(Kuhn-Munkres)算法求带权二分图的最佳匹配

    KM(Kuhn-Munkres)算法求带权二分图的最佳匹配 相关概念 这个算法个人觉得一开始时有点难以理解它的一些概念,特别是新定义出来的,因为不知道是干嘛用的.但是,在了解了算法的执行过程和原理后, ...

  5. hdu 2063 过山车(二分图最佳匹配)

    经典的二分图最大匹配问题,因为匈牙利算法我还没有认真去看过,想先试试下网络流的做法,即对所有女生增加一个超级源,对所有男生增加一个超级汇,然后按照题意的匹配由女生向男生连一条边,跑一个最大流就是答案( ...

  6. HDU 1533 KM算法(权值最小的最佳匹配)

    Going Home Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total ...

  7. 二分图带权匹配、最佳匹配与KM算法

    ---------------------以上转自ByVoid神牛博客,并有所省略. [二分图带权匹配与最佳匹配] 什么是二分图的带权匹配?二分图的带权匹配就是求出一个匹配集合,使得集合中边的权值之和 ...

  8. 【栈思想、DP】NYOJ-15 括号匹配(二)

    括号匹配(二) 描述 给你一个字符串,里面只包含"(",")","[","]"四种符号,请问你需要至少添加多少个括号才能 ...

  9. [NYOJ 15] 括号匹配(二)

    括号匹配(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:6   描述 给你一个字符串,里面只包含"(",")","[&qu ...

随机推荐

  1. php中遍历数组的方法

    参考网址:http://www.jb51.net/article/29949.htm 这三种方法中效率最高的是使用foreach语句遍历数组.从PHP4开始就引入了foreach结构,是PHP中专门为 ...

  2. U10vim程序编辑器

    vim需要多加练习. 1.你可以将vim视为vi的高级版本.vi分成三种模式:一般模式,编辑模式和命令行模式. 一般模式:以vi打开一个文件就直接进入一般模式了(这也是默认的模式).在这个模式中,你可 ...

  3. art patchoat

    Add patchoat tool to Art. Add a new executable called patchoat to art. This tool takes alreadycompil ...

  4. Instruments的使用 逻辑查错,内存泄漏分析等工具集

    原创文章,转载请注明 XCode 开发后期,要对代码进行改进和优化,查内存泄漏是其中一项重要工作,今天下午偷了点时间,把前段时间的代码稍微整理了一下,顺带用了下这个工具,还真发现了些问题.这里记录一下 ...

  5. 图片预览插件 fancyBox

    今天给大家分享一款优秀的 jquery 弹出层展示插件 fancybox. 它除了能够展示图片之外,还能够展示 flash.iframe 内容.html 文本以及 ajax 调用.我们能够通过 css ...

  6. New Hire Training Experience

    Game Description: 1. In a closed door, there will be a circle, and 30 numbers in the circle. 2. Each ...

  7. TextView 使用自定义的字体和亮点

    尊重原创:http://blog.csdn.net/yuanzeyao/article/details/40478815 如今非常多应用中喜欢使用自己定义字体,今天我就来实如今TextView中使用自 ...

  8. 怎样获取android手机联系人并按字母展示(一)

    android提供了本地数据库的查询uri,能够查询出数据: 採用一个AsyncQueryHandler来进行查询, AsyncQueryHandler自己开启了线程来进行数据查询,非常方便 prot ...

  9. Unity3D在一建筑GL材料可以改变颜色和显示样本

    void CreateLineMaterial()     {         if (!mat)         {             mat = new Material("Sha ...

  10. FusionCharts简单教程---建立第一个FusionCharts图形

    由于项目需求需要做一个报表,选择FusionCharts作为工具使用.由于以前没有接触过报表,网上也没有比较详细的fusionCharts教程,所以决定好好研究FusionCharts,同时做一个比较 ...