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. RabbitMQ安装配置和基于EasyNetQ驱动的基础使用

    一.RabbitMQ基本概念和原理 1.AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计. 2.Ra ...

  2. */美女镇楼/*>>>---PHP中的OOP-->面对过程与面对对象基础概念与内容--(封装、继承、多态)

      前  言  OOP  学习了好久的PHP,今天来总结一下PHP中的重要成员OOP 1  面向过程&面向对象 1.专注于解决一个问题的过程.面向过程的最大特点,是由一个一个的函数去解决处理这 ...

  3. weather API 天气api接口 收集整理

    腾讯 http://sou.qq.com/online/get_weather.php?callback=Weather&city=南京 中国天气-weather.com.cn http:// ...

  4. nginx反向代理cas server之1:多个cas server负载均衡配置以及ssl配置

    系统环境采用centOS7 由于cas server不支持session持久化方式的共享,所以请用其他方式代替,例如:组播复制. 为什么不支持session持久化:http://blog.csdn.n ...

  5. .Net中的AOP系列之《AOP实现类型》

    返回<.Net中的AOP>系列学习总目录 本篇目录 AOP是如何跑起来的 运行时编织 复习代理模式 动态代理 编译时编织 后期编译(PostCompiling) 来龙去脉 运行时编织 VS ...

  6. JavaScript设计模式_05_发布订阅模式

    发布-订阅模式,定义了对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都将得到通知.发布-订阅模式是使用比较广泛的一种模式,尤其是在异步编程中. /* * pre:发布-订阅 ...

  7. C#中switch的使用

    今天在网上看到有人给出这么一个程序需求,博主就拿来回忆回忆C#中switch的用法 程序需求如下: 根据星期几(一 ~日) ,输出特价菜“一”.“二”.“三”,输出“干煸扁豆6元.”“四”.“五”,输 ...

  8. 高性能队列Disruptor系列2--浅析Disruptor

    1. Disruptor简单介绍 Disruptor是一个由LMAX开源的Java并发框架.LMAX是一种新型零售金融交易平台,这个系统是建立在 JVM 平台上,核心是一个业务逻辑处理器,它能够在一个 ...

  9. Cordova各个插件使用介绍系列(一)—$cordovaSms发送短信

    详情链接地址:http://www.ncloud.hk/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/cordova-1-cordovasms/ 这是调用手机发送短信的插件 ...

  10. mysql GROUP_CONCAT获取分组的前几名

    比如说要获取班级的前3名,oracle 可以用 over partition by 来做.mysql就可以用GROUP_CONCAT  + GROUP BY + substring_index实现. ...