POJ2195 Going Home 【最小费用流】+【最佳匹配图二部】
| Time Limit: 1000MS | Memory Limit: 65536K | |
| Total Submissions: 18169 | Accepted: 9268 |
Description
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
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
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 【最小费用流】+【最佳匹配图二部】的更多相关文章
- Luogu 1559 运动员最佳匹配问题(带权二分图最大匹配)
Luogu 1559 运动员最佳匹配问题(带权二分图最大匹配) Description 羽毛球队有男女运动员各n人.给定2 个n×n矩阵P和Q.P[i][j]是男运动员i和女运动员j配对组成混合双打的 ...
- 二分图匹配之最佳匹配——KM算法
今天也大致学了下KM算法,用于求二分图匹配的最佳匹配. 何为最佳?我们能用匈牙利算法对二分图进行最大匹配,但匹配的方式不唯一,如果我们假设每条边有权值,那么一定会存在一个最大权值的匹配情况,但对于KM ...
- opencv学习之路(34)、SIFT特征匹配(二)
一.特征匹配简介 二.暴力匹配 1.nth_element筛选 #include "opencv2/opencv.hpp" #include <opencv2/nonfree ...
- KM(Kuhn-Munkres)算法求带权二分图的最佳匹配
KM(Kuhn-Munkres)算法求带权二分图的最佳匹配 相关概念 这个算法个人觉得一开始时有点难以理解它的一些概念,特别是新定义出来的,因为不知道是干嘛用的.但是,在了解了算法的执行过程和原理后, ...
- hdu 2063 过山车(二分图最佳匹配)
经典的二分图最大匹配问题,因为匈牙利算法我还没有认真去看过,想先试试下网络流的做法,即对所有女生增加一个超级源,对所有男生增加一个超级汇,然后按照题意的匹配由女生向男生连一条边,跑一个最大流就是答案( ...
- HDU 1533 KM算法(权值最小的最佳匹配)
Going Home Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- 二分图带权匹配、最佳匹配与KM算法
---------------------以上转自ByVoid神牛博客,并有所省略. [二分图带权匹配与最佳匹配] 什么是二分图的带权匹配?二分图的带权匹配就是求出一个匹配集合,使得集合中边的权值之和 ...
- 【栈思想、DP】NYOJ-15 括号匹配(二)
括号匹配(二) 描述 给你一个字符串,里面只包含"(",")","[","]"四种符号,请问你需要至少添加多少个括号才能 ...
- [NYOJ 15] 括号匹配(二)
括号匹配(二) 时间限制:1000 ms | 内存限制:65535 KB 难度:6 描述 给你一个字符串,里面只包含"(",")","[&qu ...
随机推荐
- 《javascript高级编程》读书笔记(三)变量、范围和内存的问题
第四章:变量.范围和内存的问题 检測类型:typeof是确定一个变量是字符串.数值.布尔值,还是undefined的最佳工具.可是假设变量的值是一个对象或null,typeof仅仅会返回" ...
- TestThreadPoolExecutor.java
package ; import java.io.IOException;import java.io.InputStream;import java.util.List;impo ...
- 该Tiled地图制作拿到项目~~这是偷懒,为了直接复制后写来
1.现在,.h声明private: cocos2d::CCSprite* ninja; cocos2d::CCTMXTiledMap* tileMap; 然后.cpp中增加tileMap = CCT ...
- [ios仿系列]仿支付宝手势解码
呀~.这么快就转到ios阵营了???.android还有那么多坑呢???为此我也仅仅能啃着馒头留下屈辱的眼泪了. . 本次因为开发公司产品的android版,继而ios版也负责一部分.当中一部分就是手 ...
- 站点搭建从零開始(四) server的配置
原文发表在我的个人站点,欢迎大家訪问~转载请保留本段,或注明原文:http://www.hainter.com/website-primer-4 域名解析设置好了,通常我们就能够訪问我们的网站了,上篇 ...
- JDK基本介绍
JDK这是Java Development Kit 缩写,中国被称为Java开发套件.由SUN该公司提供.这是Java应用程序开发提供了编译和执行环境,所有的Java写程序都依赖于它. JDK能够将J ...
- 清除Android工程中没用到的资源(转)
项目需求一改再改,UI一调再调,结果就是项目中一堆已经用不到但却没有清理的垃圾资源,不说工程大小问题,对新进入项目的人或看其他模块的代码的人来说,这些没清理的资源可能也可能会带来困扰,所以最好还是清理 ...
- Source Insight 光标变粗设置NotePad++光标设置
为了更好的查看文档和代码,避免半天都找不到光标的情况,故做此说明 Source Insight 光标变粗 菜单中 Options --->Preferences --->Typing -- ...
- A WPF File ListView and ComboBox
源码下载: Download FileListView_Version_2.zip Download FileListView_Version_2_Binaries.zip Download File ...
- 基于Tkinter利用python实现颜色空间转换程序
主要基于colorsys实现,例子是从hls转换到rgb,假设要换颜色空间非常easy仅仅须要改动一个函数 用到了Scale和Canvas组件 代码例如以下: from Tkinter import ...