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 ...
随机推荐
- zoj 3822 Domination(2014牡丹江区域赛D称号)
Domination Time Limit: 8 Seconds Memory Limit: 131072 KB Special Judge Edward is the headm ...
- 实现Android ListView 自动加载更多内容
研究了几个小时终于实现了Android ListView 自动加载的效果. 说说我是怎样实现的.分享给大家. 1.给ListView增加一个FooterView,调用addFooterView(foo ...
- 加入指数(IOS开发)
该指数是用来协助查询. 原则上: - 索引的标题是不完全一样的标题显示: - 指数应该具有一定的代表性,它可表示一组数据: - 假设索引列表视图.在一般情况下不再使用扩展视图. (easy指向) 会又 ...
- JS多语种方式
方案: 在不同的移动平台(IOS.Android)上,并建立了HTML页面通信框架.主要业务逻辑HTML发展:我要支持多语言开发. 动机: 通过积极主动的信息方式,前一页完成初始化,获取当前语言选项. ...
- Sql Server函数全解<四>日期和时间函数
原文:Sql Server函数全解<四>日期和时间函数 日期和时间函数主要用来处理日期和时间值,本篇主要介绍各种日期和时间函数的功能和用法,一般的日期函数除了使用date类型的参数外, ...
- android学习七(创建自己定义控件)
前面学习的是android的基本控件和布局的使用,可是主要的控件和布局有时候并不能实现复杂的布局.我们来看下各种控件和布局的关系. 可见全部的控件都是直接或者间接的继承自View的,全部的布局都是直接 ...
- SQL在declare声明变量
在sql添加的声明变量. declare @local_variable data_type 你需要指定一个变量声明的类型, 能够使用set和select对变量进行赋值, 在sql语句中就能够使用@l ...
- Lua语言在Wireshark中使用(转)
1. 检查Wireshark的版本是否支持Lua 打开Wireshark,点击“HelpàAbout Wireshark”菜单,查看弹出的对话框,如果有“with Lua 5.1”表示支持 ...
- 记View跨界平局
<?xml version="1.0" encoding="utf-8"? > <RelativeLayout xmlns:android=& ...
- 查看linux信息
1.操作系统内核 cat /proc/version 2.操作系统版本 head -n 1 /etc/issue # 查看操作系统版本 3.查看cpu信息 more /proc/cpuinfo --- ...