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. 程序员的视角:java 线程(转)

    在我们开始谈线程之前,不得不提下进程.无论进程还是线程都是很抽象的概念,有一个关于进程和线程很形象的比喻能帮我们更好的理解. 进程就像个房子,房子是一个包含了特定属性的容器,例如空间大小.卧室数量等. ...

  2. 一个非常优秀的前端框架--BootStrap

    在接触BootStrap之前,也许我们已经度过了很多关于前端开发的框架及

  3. Andriod开发之浏览器开发(WebView)

    1.创建一个WebView在XML文件 <WebView android:id="@+id/webView" android:layout_width="match ...

  4. css3仿山猫侧边栏

    演示:http://jsfiddle.net/Adce2/ 其主要思想: 1, 先画边栏html. 2, 使用css3分别财产close sidebar-content动图片. 3, 使用css3的k ...

  5. Lucene40SkipListWriter

    多级跳跃表是保存在tim文件里的. tip是term index,tim是term dictionary.记忆方法是,p是pointer因此是term index. 这个类会保存多个level的las ...

  6. WebService什么?

    一.前言 我们或多或少都听过WebService(Web服务),有一段时间非常多计算机期刊.书籍和站点都大肆的提及和宣传WebService技术.当中不乏非常多吹嘘和做广告的成分.可是不得不承认的是W ...

  7. effective c++ 条款11 Handle assignment to self in operator=

    赋值给自己,听起来有些不可思议,但是却要引起重视,它很容易把自己隐藏起来. 例如 1 a[i]=a[j]; 如果 i, j的值一样? 2 *px=*py; 如果px py指向同一个object 3   ...

  8. Codeforces 385B Bear and Strings

    题目链接:Codeforces 385B Bear and Strings 记录下每一个bear的起始位置和终止位置,然后扫一遍记录下来的结构体数组,过程中用一个变量记录上一个扫过的位置,用来去重. ...

  9. 返璞归真 asp.net mvc (1) - 添加、查询、更新和删除的 Demo

    原文:返璞归真 asp.net mvc (1) - 添加.查询.更新和删除的 Demo [索引页] [源码下载] 返璞归真 asp.net mvc (1) - 添加.查询.更新和删除的 Demo 作者 ...

  10. Codeforces Helpful Maths

    Xenia the beginner mathematician is a third year student at elementary school. She is now learning t ...