POJ2195 Going Home 最小费用最大流

Going Home

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 25567   Accepted: 12838

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

Source

Pacific Northwest 2004

题意:

有k个人,k间房子,每人进入一个房子,求最小的总距离
分析:
对每条边取相反数,然后得到的结果再取相反数,就能得到最小权匹配

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
#define MAXN 105using namespace std;int n;//二分图顶点集的大小
int a[MAXN][MAXN];//a[i][j]表示i到j的权值
int vx[MAXN],vy[MAXN];
int lx[MAXN],ly[MAXN];//同时调节两个数组,使得权值和最大
int pre[MAXN];//记录顶点集n2中点x在顶点集n1中所匹配的点x的编号
int slack[MAXN];//松弛操作
int N,M;//N行M列
int cnth,cntm;
struct point{int x,y;
}tmph[MAXN],tmpm[MAXN];
char st[MAXN][MAXN];bool dfs(int index)
{vx[index]=1;for(int i=1;i<=n;i++){if(!vy[i]&&lx[index]+ly[i]==a[index][i]){//这个条件下使用匈牙利算法vy[i]=1;//这个房子没人住或者可以让住这个房子的人找另外的房子if(!pre[i]||dfs(pre[i])){pre[i]=index;return 1;}}else if(!vy[i]&&lx[index]+ly[i]>a[index][i])slack[i]=min(slack[i], lx[index]+ly[i]-a[index][i]);}return 0;
}int KM()
{memset(ly,0,sizeof(ly));//首先把每个居民出钱最多的那个房子给他for(int i=1;i<=n;i++){lx[i]=-INF;for(int j=1;j<=n;j++)lx[i]=max(lx[i],a[i][j]);}int ans=0,d;memset(pre,0,sizeof(pre));//给第i位居民分配房子for(int i=1;i<=n;i++){memset(slack,INF,sizeof(slack));while(1){memset(vx,0,sizeof(vx));memset(vy,0,sizeof(vy));if(dfs(i))break;d=INF;for(int i=1;i<=n;i++)if(!vy[i])d=min(d,slack[i]);//找到最小松弛量if(d==INF) return -1;           //no matchingfor(int j=1;j<=n;j++){if(vx[j]) lx[j]-=d;if(vy[j]) ly[j]+=d;}}}for(int i=1;i<=n;i++)ans+=a[pre[i]][i];return ans;
}int main()
{while(~scanf("%d %d", &N, &M)){if(!N&&!M)break;cnth=cntm=0;getchar();for(int i=1;i<=N;i++){for(int j=1;j<=M;j++){scanf("%c",&st[i][j]);if(st[i][j]=='m')cntm++,tmpm[cntm].x=i, tmpm[cntm].y=j;if(st[i][j]=='H')cnth++,tmph[cnth].x=i, tmph[cnth].y=j;}getchar();}n=cntm;for(int i=1;i<=cntm;i++)for(int j=1;j<=cnth;j++)a[i][j]=-(abs(tmpm[i].x-tmph[j].x)+abs(tmpm[i].y-tmph[j].y));printf("%d\n",-KM());}return 0;
}

Java

import java.math.*;
import java.util.*;public class Main {static int inf=(int)1e8+7;static int maxn=110;static int n;//n个球,n个洞static int[][] w=new int[maxn][maxn];//w[i][j]表示i到j的权值static int[] lx=new int[maxn];static int[] ly=new int[maxn];static int[] link=new int[maxn];static int[] slack=new int[maxn];static boolean[] visx=new boolean[maxn];static boolean[] visy=new boolean[maxn];static boolean dfs(int x) {visx[x]=true;for(int y=1;y<=n;y++) {//if(visy[y])  continue;int t=lx[x]+ly[y]-w[x][y];if(!visy[y]&&t==0) {visy[y]=true;if(link[y]==0||dfs(link[y])) {link[y]=x;return true;}}else if(!visy[y]&&lx[x]+ly[y]>w[x][y])slack[y]=Math.min(slack[y], lx[x]+ly[y]-w[x][y]);}return false;}static int km() {for(int i=0;i<maxn;i++) {lx[i]=-inf;ly[i]=0;link[i]=0;}for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)lx[i]=Math.max(lx[i], w[i][j]);for(int i=1;i<=n;i++) {for(int j=1;j<=n;j++) slack[j]=inf;while(true) {for(int k=1;k<maxn;k++) {visx[k]=false;visy[k]=false;}if(dfs(i))   break;int d=inf;for(int k=1;k<=n;k++)if(!visy[k]&&d>slack[k])d=slack[k];if(d==-1) return -1;// no matchingfor(int k=1;k<=n;k++) {if(visx[k])   lx[k]-=d;if(visy[k])   ly[k]+=d;}}}int ans=0;for(int i=1;i<=n;i++)ans+=w[link[i]][i];return ans;}public static void main (String[] args) {Scanner cin=new Scanner(System.in);while(cin.hasNext()) {int[] ball_x=new int[maxn];int[] ball_y=new int[maxn];int[] hole_x=new int[maxn];int[] hole_y=new int[maxn];int bk=1,hk=1;int M=cin.nextInt();int N=cin.nextInt();String str="";if(M==0&&N==0)  break;for(int i=0;i<M;i++) {str=cin.next();for(int j=0;j<N;j++) {if(str.charAt(j)=='m') {ball_x[bk]=i;ball_y[bk]=j;bk++;}else if(str.charAt(j)=='H') {hole_x[hk]=i;hole_y[hk]=j;hk++;}}}n=bk-1;//System.out.println(n);for(int i=1;i<=n;i++) {for(int j=1;j<=n;j++) {w[i][j]=-Math.abs(ball_x[i]-hole_x[j])-Math.abs(ball_y[i]-hole_y[j]);//System.out.print(-w[i][j]+" ");}//System.out.println();}System.out.println(-km());}cin.close();}
}

POJ 2195 Going Home 二分图的最大权匹配相关推荐

  1. hdu 2853Assignment (二分图的最大权匹配)

    //hdu2853 //二分图的最大权匹配,图中有一些边,在等权值的条件下有优先选择权. //因为是选n个进行匹配,我们将每条边的权值扩大(n+1)倍,这样每条边相对大小是一样的 //对于有优先选择权 ...

  2. Java实现二分图的最大权匹配

    1 问题描述 何为二分图的最大权匹配问题? 最大权二分匹配问题就是给二分图的每条边一个权值,选择若干不相交的边,得到的总权值最大. 2 解决方案 解决这个问题可以用KM算法.理解KM算法需要首先理解& ...

  3. POJ - 2195 Going Home(二分图最小权匹配+KM+思维建边/最小费用最大流)

    题目链接:点击查看 题目大意:给出一个n*m的地图,现在有一定数量的小人要回到屋子里去,题目保证图中的小人和屋子的数量是一致的,小人回到小屋的距离是两个点坐标的曼哈顿距离,每个小屋只能容纳一个小人,现 ...

  4. java 二分图带权匹配_算法笔记_139:二分图的最大权匹配(Java)

    packagecom.liuzhen.practice;importjava.util.Scanner;public classMain {public static int MAX = 100;pu ...

  5. hdu 3395(费用流,二分图的最大权匹配)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3395 解题思路: 这个构图很容易出错,最开始都容易想,把每个点拆开,分为攻击和被攻击的,建图如下: 源 ...

  6. 【算法笔记】二分图最大权匹配 - KM算法(dfs版O(n4) + bfs版O(n3))

    整理的算法模板合集: ACM模板 匈牙利算法又称为 KM 算法,可以在 O(n3)O(n^3)O(n3) 时间内求出二分图的 最大权完美匹配 . 考虑到二分图中两个集合中的点并不总是相同,为了能应用 ...

  7. 二分图最大权匹配 KM算法

    KM算法的正确性基于以下定理: 若由二分图中所有满足A[i]+B[i]=w[i][j]的边C(i,j)构成的子图(即相等子图)有完备匹配,那么这个完备匹配就是二分图的最大权匹配 基本概念 1.完备匹配 ...

  8. KM算法 最优匹配(最大权匹配) hdu 2255 奔小康赚大钱 最小权匹配 poj 2195 Going Home

    最大权二分匹配问题就是给二分图的每条边一个权值,选择若干不相交的边,得到的总权值最大.解决这个问题可以用KM算法.理解KM算法需要首先理解"可行顶标"的概念.可行顶标是指关于二分图 ...

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

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

最新文章

  1. LeetCode简单题之按照频率将数组升序排序
  2. python3.9.0 print_关于 Python 3.9,那些你不知道的事
  3. 轰动程序员圈的大事:女程序员将代码写到退休,返聘再续传奇
  4. 设置Exchange 2010附件大小限制原则
  5. 牛客网数据开发题库_数据库刷题—牛客网(21-30)
  6. mysql字段唯一确定_验证表里某不确定的字段的值是否唯一的方法?
  7. 从imdb爬取ml-100k的电影封面
  8. JSON for Modern C++ 3.6.0 发布
  9. 贝叶斯分类器基本理论
  10. CentOS6系统编译部署LAMP(Linux, Apache, MySQL, PHP)环境
  11. IS-IS详解(九)——IS-IS 骨干区域与非骨干区域访问基础
  12. mysql 中的bool值
  13. 企业传播需要拥有的5个风险意识
  14. mysql 联合主键 null_提问关于 mysql得联合主键和复合主键的问题
  15. Python 如何画出漂亮的地图?
  16. Java:使用POI导出Excel文件后打开文件提示因为文件格式或文件扩展名无效而无法打开
  17. 使用Docker部署Spring-Boot-项目,带劲!
  18. 2015年终总结-青春如歌
  19. VS Code错误 “preloads: Could not find renderer” 解决办法
  20. poker网络 -2

热门文章

  1. Linux centosVMware Tomcat介绍、安装jdk、安装Tomcat
  2. 第1章 认识jQuery
  3. OA项目15:权限管理实体设计及映射
  4. PHP用空格分割文本为数组的方法
  5. python程序流程控制_python流程控制
  6. 检验是否服从同一分布
  7. 2019年四月计算机语言排名,2019编程语言排行榜_编程语言排行榜2019年4月 TIOBE编程语言排行榜2019年最...
  8. oss图片上传api_交互式核保系统:api明细:图片上传oss接口
  9. 模板 字段_Anki学习之路(08)|什么是Anki模板类型?什么是字段?
  10. python定义匿名函数关键字_Python(11):Python函数基础(定义函数、函数参数、匿名函数)...