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. superagent和request结果转换区别

    superagent和request结果转换区别 使用superagent和request抓取页面内容时,两个抓取内容都可以被cheerio进行处理.但处理时有个细微差别. 1. 使用superage ...

  2. Swoole笔记(二)

    本文示例代码详见:https://github.com/52fhy/swoole_demo. Task 我们可以在worker进程中投递一个异步任务到task_worker池中.此函数是非阻塞的,执行 ...

  3. Predix Asset Service深度分析

    前言 在IIOT领域,面临着保存海量数据的挑战,具体到Asset层面,则要保存物理对象,逻辑对象,复杂的关系,并支持对象间的组合,分类,标签和高效查询.总结来说,可以归纳为如下几种需求:   灵活的建 ...

  4. 乐视开放平台技术架构-servlet和spring mvc篇

    在乐视风口浪尖的时候,敢于站出来说我是乐视的而不怕被打脸的,也就是我了.就算我以后不在乐视了,提起来在乐视工作过,我也还是挺骄傲的.因为这是一个有理想,敢拼敢干的公司.想起复仇者联盟里Fury指挥官的 ...

  5. SQL SERVER大话存储结构(6)_数据库数据文件

            数据库文件有两大类:数据文件跟日志文件,每一个数据库至少各有一个数据文件或者日志文件,数据文件用来存储数据,日志文件用来存储数据库的事务修改情况,可用于恢复数据库使用.     这里分 ...

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

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

  7. JavaScript实现图片拖拽、粘贴上传

    前些日子为老婆做了一个web管理商品的工具,因为商品的图片比较多并且还需要剪裁图,为了上传图片方便加了一个拖拽.粘贴上传的功能. 我已经把代码整理出来放到GitHub上了,有兴趣的朋友可以下来玩玩. ...

  8. 关于MATLAB处理大数据坐标文件201763

    目前已经找出26条特征 ,但是提交数据越来越少,给我的感觉是随机森林画的范围越来越小,输出的机器数据也越来越少,我自认为特征没太大问题 我已经将不懂之处列了出来,将于明天咨询大师级人物

  9. MySQL数据表的创建、查看、插入

    数据表:数据表(或称表)是数据库最重要的组成部分之一,是其他对象的基础.     1.首先我们打开一个数据库(这里我打开的是新创建的一个aaa数据库). 打开数据库:use + 数据库名;     2 ...

  10. select change事件给其它元素赋值,本select的value或tex

    select change事件给其它元素赋值,本select的value或textonchange='$("#areaname").val($("option:selec ...