题意:

给一个n*m的矩阵,其中由k个人和k个房子,给每个人匹配一个不同的房子,要求所有人走过的曼哈顿距离之和最短。

输入:

多组输入数据。

每组输入数据第一行是两个整型n, m,表示矩阵的长和宽。

接下来输入矩阵。

输出:

输出最短距离。

题解:

标准的最小费用最大流算法,或者用KM算法。由于这里是要学习费用流,所以使用前者。

最小费用最大流,顾名思义,就是在一个网络中,不止存在流量,每单位流量还存在一个费用。由于一个网络的最大流可能不止一种,所以,求出当前网络在流量最大的情况下的最小花费。

直接百度百科最小费用最大流算法,可以看到两种思路——

  1. 先求出最大流。然后寻找是否存在路径,可以使这个网络在最大流不变的情况下减小费用。如果存在,则改变网络。不停迭代,知道不存在更优的路径为止——但是我还没有找到这种方法的实现方式。我自己也没有试着实现。
  2. 在网络之外构造一个新图,这张图记录已经存在的路径的长度(即此路径单位流量的费用),需要注意的是路径是有向路径(反向路径的长度是正向路径的相反数,原因和最大流中每选择一条边,都要给网络构造)。然后寻找增广路径(也就是从源点到汇点的一条路),这条路同时满足在构造的图是最短路。然后按照求最大流的方法修改原网络,反复迭代,保证每次找到的增广路都是当前残余网络在构造的图中的最短路。那么最终得到的最大流一定是最小费用最大流(贪心大法)。

以上是算最小费用最大流的方法。

具体的算法,可以使用EK+spfa算法来实现。

针对这道题,我们需要先构造网络。

我们设0节点为源点,接下来1——k节点为人,k+1——2*k为房子,2*k+1为汇点。

源点到每个人连一条边,每个人到每个房子连一条边,每个房子到汇点连一条边(不要忘了是有向边),每条边的权为1。

接下来构造费用图。源点到每个人一条边,权值为0,每个人到每个房子一条边,权值为它们之间的曼哈顿距离。每个放在到汇点一条边,权值为0。

然后带到算法里计算。

实现见代码——

 #include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std; const int N = ;
const int M = ; struct Node
{
int x, y;
}man[N], house[N]; //人,房子的横纵坐标 char mp[N][N];
int cost[*N][*N], flow[*N][*N]; //距离图和流网络
int pre[*N], low[*N], dis[*N]; //分别记录当前节点的父节点,当前路径的最小流量,spfa中的最短距离
bool vis[*N]; //标记当前节点是否在队列中
int n, m;
int ans;
int mn, hs, k, kk; //分别表示人的数量+1,房子的数量+1,人的数量,邻接矩阵每一维的大小 void init()
{
mn = , hs = ;
for(int i = ; i < n; i++)
{
scanf("%s", mp[i]);
for(int j = ; j < m; j++)
{
if(mp[i][j] == 'm') {man[mn].x = i; man[mn++].y = j;}
if(mp[i][j] == 'H') {house[hs].x = i; house[hs++].y = j;}
}
}
k = hs-;
kk = *k+;
for(int i = ; i < kk; i++)
{
for(int j = ; j < kk; j++) cost[i][j] = M;
}
memset(flow, , sizeof(flow));
for(int i = ; i <= k; i++)
{
for(int j = k+; j < kk; j++)
{
cost[i][j] = abs(man[i].x-house[j-k].x)+abs(man[i].y-house[j-k].y); //人到房子的距离为曼哈顿距离
cost[j][i] = -cost[i][j]; //反向距离
flow[i][j] = ; //人到房子的流网络
}
cost[i][] = cost[][i] = ; //源点到人,人到源点的距离
flow[][i] = ; //源点到人的流网络
cost[i+k][kk] = cost[kk][i+k] = ; //汇点到房子,房子到汇点的距离
flow[i+k][kk] = ; //房子到汇点的流网络
}
ans = ;
} int Min(int x, int y)
{
return x < y ? x : y;
} bool spfa()
{
for(int i = ; i <= kk; i++)
{
dis[i] = M;
pre[i] = -;
vis[i] = ;
low[i] = M;
}
queue<int> que;
que.push();
vis[] = ;
dis[] = ;
while(!que.empty())
{
int p = que.front();
que.pop();
vis[p] = ;
for(int i = ; i <= kk; i++)
{
if(flow[p][i] && dis[i] > dis[p]+cost[p][i])
{
dis[i] = dis[p]+cost[p][i];
pre[i] = p;
low[i] = Min(low[p], flow[p][i]);
if(!vis[i])
{
vis[i] = ;
que.push(i);
}
}
}
}
return dis[kk] != M;
} void work()
{
while(spfa()) //如果存在路径,则计算流量
{
int x = kk;
while(pre[x] != -)
{
flow[pre[x]][x] -= low[kk];
flow[x][pre[x]] += low[kk];
x = pre[x];
}
ans += dis[kk]; //计算距离和
}
} void outit()
{
printf("%d\n", ans);
} int main()
{
while(~scanf("%d%d", &n, &m) && (n+m))
{
init();
work();
outit();
}
return ;
}

【进阶——最小费用最大流】hdu 1533 Going Home (费用流)Pacific Northwest 2004的更多相关文章

  1. Going Home HDU - 1533(最大费用最小流)

    On a grid map there are n little men and n houses. In each unit time, every little man can move one ...

  2. hdu 1533 KM或费用流

    以前用KM写过,现在再用费用流写. #include <iostream> #include <cstdio> #include <cstring> #includ ...

  3. hdu 1533(最小费用最大流)

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

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

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

  5. [ACM] HDU 1533 Going Home (二分图最小权匹配,KM算法)

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

  6. 【HDU 1533】 Going Home (KM)

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

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

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

  8. My Brute HDU - 3315(KM || 费用流)

    题意: 有S1到Sn这n个勇士要和X1到Xn这n个勇士决斗,初始时,Si的决斗对象是Xi. 如果Si赢了Xi,那么你将获得Vi分,否则你将获得-Vi分. Si和Xi对决时,Si有初始生命Hi,初始攻击 ...

  9. HDU 1533 Going Home(KM完美匹配)

    HDU 1533 Going Home 题目链接 题意:就是一个H要相应一个m,使得总曼哈顿距离最小 思路:KM完美匹配,因为是要最小.所以边权建负数来处理就可以 代码: #include <c ...

随机推荐

  1. mmap 的理解

    mmap 的理解 采用共享内存通信的一个显而易见的好处 是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝.对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存 ...

  2. @RequestBody 的正确使用办法

    1.以前一直以为在SpringMVC环境中,@RequestBody接收的是一个Json对象,一直在调试代码都没有成功,后来发现,其实 @RequestBody接收的是一个Json对象的字符串,而不是 ...

  3. 五分钟轻松搞定产品需求文档!这可能史上最全PRD文档模板

    本文由  @JustWu 原创发布于社区 为什么写这篇文章? 第一:写PMCAFF的PRD文档,大家都是用户,比较好参考与理解,方便大家来找我写的不好的地方. 第二:我在自学PRD文档的编写过程中,总 ...

  4. iOS开发多线程--技术方案

    pthread 实现多线程操作 代码实现: void * run(void *param) {    for (NSInteger i = 0; i < 1000; i++) {         ...

  5. schtasks确实可以绕过UAC,简直不可思议啊~~

    https://msdn.microsoft.com/en-us/library/windows/desktop/bb736357(v=vs.85).aspx

  6. Drozer安装

    (1)JDK安装 http://www.cnblogs.com/linbc/p/4319509.html http://blog.csdn.net/qq_31988895/article/detail ...

  7. Android 时间戳简单转化

    时间戳就是如1377216000000 这种格式我们在mysql数据库中会经常用到把时间转换成时间戳或把时间戳转换成日期格式了,下面我来介绍安卓中时间戳操作转换方法. 一.原理 时间戳的原理是把时间格 ...

  8. 文章投稿 latex 生成 pdf的字体Embeded问题解决(转自兵马俑BBS)

    此法可以把所有字体转为Embedded,先生成*.ps文件,下载ghostscrip8.51和GSView4.7 安装,用gsview4.7转换*.ps->*.pdf,在gsview中File- ...

  9. ftp 建立、配置、实用软件 fileZilla server

    ftp 建立.配置.实用软件  fileZilla server

  10. 了解ThinkPHP(一)

    1.项目开发,中,会遇到的问题: 1). 多人开发项目,分工不合理,(html   php   mysql) 2). 代码风格不一样,后期维护十分困难 3). 项目生命周期十分短,项目生命没有延续性, ...