POJ 2195 Going Home (带权二分图匹配)

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

Http

POJ:https://vjudge.net/problem/POJ-2195

Source

带权二分图的匹配

题目大意

有n个人和n个房间,每个人只能并且必须进到一个房间,现在求所有人走到房间的总路径最小。

解决思路

这道题是带权二分图的KM算法。关于KM算法,在我的这道题中已经讲过了,基本的模型不再多说。笔者只讲一下在这道题上要注意什么。

首先,在上面那道题中我们用KM算法是求权值和最大的匹配,而到了这道题中却成了权值最小的匹配,如何解决呢?

一个比较好的方法是把所有的权值都置为负数,即原来距离是d,现在我们把权值置为-d,那么我们还是用上面那道题的方法,跑出最大值(同样也是负数),那么这时我们就可以保证“最大值”的绝对值是最小的。

另一种方法就是更改代码中Wx,Wy数组的计算,笔者使用的就是这种方法。稍微复杂一点,要修改的地方我在代码中已经标记出来啦。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
using namespace std; class Edge
{
public:
int v,dist;
}; class Position
{
public:
int x,y;
}; const int maxmap=200;
const int maxN=200;
const int inf=2147483647; int n,m;
int G[maxN][maxN];
int Match_man[maxN];
int Match_house[maxN];
int Wx[maxN];
int Wy[maxN];
vector<Position> House;
vector<Position> Man;
bool use_man[maxN];
bool use_house[maxN]; bool Hungary(int u); int main()
{
while (cin>>n>>m)
{
if ((n==0)&&(m==0))
break;
House.clear();
Man.clear();
char str[maxN];
for (int i=1;i<=n;i++)
{
cin>>str;
for (int j=0;j<m;j++)
if (str[j]=='H')
{
House.push_back((Position){i,j+1});
}
else
if (str[j]=='m')
{
Man.push_back((Position){i,j+1});
}
}
//cout<<Man.size()<<endl;
//cout<<"A"<<endl;
for (int i=0;i<=Man.size();i++)
for (int j=0;j<=House.size();j++)
G[i][j]=-1;
//cout<<"B"<<endl;
memset(Match_house,-1,sizeof(Match_house));
memset(Match_man,-1,sizeof(Match_man));
memset(Wy,0,sizeof(Wy));
for (int i=0;i<Man.size();i++)
{
//cout<<i<<endl;
Wx[i+1]=inf;
for (int j=0;j<House.size();j++)
{
int d=abs(Man[i].x-House[j].x)+abs(Man[i].y-House[j].y);
G[i+1][j+1]=d;
Wx[i+1]=min(Wx[i+1],d);//注意这里要的是最小值
}
}
//cout<<"C"<<endl;
for (int i=1;i<=Man.size();i++)
{
do
{
memset(use_man,0,sizeof(use_man));
memset(use_house,0,sizeof(use_house));
if (Hungary(i))
break;
int D=inf;
for (int j=1;j<=Man.size();j++)
if (use_man[j]==1)
for (int k=1;k<=House.size();k++)
if ((G[j][k]!=-1)&&(use_house[k]==0))
{
D=min(D,G[j][k]-Wx[j]-Wy[k]);;//这里因为Wx,Wy的意义变成了最小值,所以G[j][k]比Wx[j]+Wy[k]要大,所以这里的D就成了当前能放入的权值最小的边(在原KM算法中是最大的)
}
//cout<<"D "<<D<<endl;
for (int j=1;j<=Man.size();j++)
if (use_man[j]==1)
Wx[j]=Wx[j]+D;//注意这里Wx变成了-D,而Wy成了+D
for (int j=1;j<=House.size();j++)
if (use_house[j]==1)
Wy[j]=Wy[j]-D;
}
while (1);
}
int Ans=0;
for (int i=1;i<=House.size();i++)
Ans+=G[Match_house[i]][i];
cout<<Ans<<endl;
}
return 0;
} bool Hungary(int u)
{
use_man[u]=1;
for (int i=1;i<=House.size();i++)
if ((G[u][i]!=-1)&&(Wx[u]+Wy[i]==G[u][i])&&(use_house[i]==0))
{
use_house[i]=1;
if ((Match_house[i]==-1)||(Hungary(Match_house[i])))
{
Match_house[i]=u;
Match_man[u]=i;
return 1;
}
}
return 0;
}

POJ 2195 Going Home (带权二分图匹配)的更多相关文章

  1. POJ 2195 Going Home | 带权二分图匹配

    给个地图有人和房子 保证人==房子,每个人移动到房子处需要花费曼哈顿距离的代价 问让人都住在房子里最小代价 显然是个带权二分图最大匹配 转化成以一个网络,规定w是容量,c是代价 1.S向人连边,w=1 ...

  2. 运动员最佳匹配问题 KM算法:带权二分图匹配

    题面: 羽毛球队有男女运动员各n人.给定2 个n×n矩阵P和Q.P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势:Q[i][j]是女运动员i和男运动员j配合的女运动员竞赛优势. ...

  3. 费用流模板(带权二分图匹配)——hdu1533

    /* 带权二分图匹配 用费用流求,增加源点s 和 汇点t */ #include<bits/stdc++.h> using namespace std; #define maxn 1000 ...

  4. hdu5045:带权二分图匹配

    题目大意 : n个人 做m道题,其中 每连续的n道必须由不同的人做 已知第i人做出第j题的概率为pij,求最大期望 思路:考虑每连续的n道题 都要n个人来做,显然想到了带权的二分图匹配 然后就是套模板 ...

  5. Glorious Brilliance (最短路 + 带权二分图匹配)

    这是一道代码大题.一开始读错题意了,然后理解成直接看上去的那种相邻,然后想不通好久!!! 把不同联通的图分离出来,然后先预处理一下形成之后的相邻图的状态,然后根据01确定哪一些是需要更换状态的,然后建 ...

  6. [NOI2012]美食节——费用流(带权二分图匹配)+动态加边

    题目描述 小M发现,美食节共有n种不同的菜品.每次点餐,每个同学可以选择其中的一个菜品.总共有m个厨师来制作这些菜品.当所有的同学点餐结束后,菜品的制作任务就会分配给每个厨师.然后每个厨师就会同时开始 ...

  7. [HAOI2008]移动玩具(状压&带权二分图)

    题目描述 • 一个 4 × 4 的 0/1 矩阵 • 每次可以交换相邻两个元素 • 求从初始状态到目标状态的最小交换次数 输入格式 前四行,每行一个长为 4 的 0/1 字符串,描述初始状态. 后四行 ...

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

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

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

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

随机推荐

  1. JVM学习笔记三:垃圾收集器与内存分配策略

    内存回收与分配重点关注的是堆内存和方法区内存(程序计数器占用小,虚拟机栈和本地方法栈随线程有相同的生命周期). 一.判断对象是否存活? 1. 引用计数算法 优势:实现简单,效率高. 致命缺陷:无法解决 ...

  2. Python常用的第三方库

    最近学习python 做些数据挖掘相关的练习,涉及到很多第三方的库,所以做一总结. Setuptools 可以让程序员更方便的创建和发布 Python 包,特别是那些对其它包具有依赖性的状况. 我特别 ...

  3. javaCV开发详解之7:让音频转换更加简单,实现通用音频编码格式转换、重采样等音频参数的转换功能(以pcm16le编码的wav转mp3为例)

    javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...

  4. Sqlmap注入Base64编码的注入点

    不小心删了,找快照才找到的.补回来... 上次遇到一个Base64的注入点,手工注入太麻烦,于是在网上看了一下sqlmap Base64注入的方法,如下: sqlmap -u http://xxxx. ...

  5. git rebase -i命令修改commit历史

    [TOC] 修改commit历史的前提 修改历史的提交是可能有风险的,是否有风险取决于commit是否已经推送远程分支,未推送,无风险,如果已推送,就千万不要修改commit了. 修改commit历史 ...

  6. 模拟jquery底层链式编程

    //特点1:快级作用域,程序启动自动执行 //内部的成员变量,外部无法访问(除了var) //简单的函数链式调用 function Dog(){ this.run=function(){ alert( ...

  7. ArcGIS API for JavaScript根据两个点坐标在地图上画线

    ArcGIS API for JavaScript根据两个点坐标在地图上画线比如说a(xxxx,xxxxx),b(xxxx,xxxxx).利用这两个点画一条线 var polyline = new e ...

  8. scrapy代理的设置

    scrapy代理的设置 在我的上一篇文章介绍了scrapy下载器中间件的使用,这里的scrapyIP的代理就是用这个原理实现的,重写了下载器中间件的process_request(self,reque ...

  9. SICP-2.2-数据的抽象

    数据的抽象 生活中有许多的事物具有复合结构,例如地理位置所用的经纬度,便是通过一个复合结构来代表位置,在我们的程序当中,我们设法将经度纬度组合成一对,我们既可以把他们当做一个整体单元来进行操作,而且也 ...

  10. golang 私钥"加密"公钥"解密"

    ---恢复内容开始---   之前工作主要使用C/C++与银行/第三方支付对接,但C/C++无法满足客户"当天给协议明天实盘上载"的开发速度以及现公司一些特殊情况,所以决定用go来 ...