POJ-2195 Going Home (最小费用最大流初学 && 最大权二分匹配—KM算法)

KM算法 最优匹配(最大权匹配) hdu 2255 奔小康赚大钱 最小权匹配 poj 2195 Going Home 最大权二分匹配问题就是给二分图的每条边一个权值,选择若干不相交的边,得到的总权值最大。解决这个问题可以用KM算法。理解KM算法需要首先理解“可行顶标”的概念。可行顶标是指关于二分图两边的每个点的一个值lx[i]或ly[j],保证对于每条边w[i][j]都有lx[i]+ly[j]-w[i][j]>=0。如果所有满足lx[i]+ly[j]==w[i][j]的边组成的导出子图中存在一个完美匹配,那么这个 阅读详情
Going Home
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 16870 Accepted: 8636

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


思路:

       最小费用最大流初学,模板题;

       可以说是利用EK算法来确定最大流,利用SPFA算法判断存不存在可行流,并选择出最小费用的可行流;两者结合即可求出最小费用最大流;

       也可用最大权二分匹配KM算法解决,但须注意,这儿求的是最小花费,所以用KM时要把权值 * -1,最后再把结果 * -1即可,也当做模板题整理!


最小费用最大流代码:

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <queue>
#define INF 0x7fffffff
#define EN 200000
#define N 300

using namespace std;

struct Edge{
	int u, v;		// 起点,终点
	int w, c;		// 代价,流量
	int next;		// 类似单链表中的next指针
};

struct Node{
	int x;
	int y;
};

Edge edge[EN];		// 边
Node H[N], M[N];
int ep = 0; 
bool vis[N];
int pre[N];			// 保存i的父节点
int min_weight[N];	// 原SPFA最小距离(dis)数组,此处保存最小代价
int head[N];		// 临界表

void AddEdge(int u, int v, int w, int c)
{
	edge[ep].u = u;			// 建立正向边
	edge[ep].v = v;
	edge[ep].w = w;
	edge[ep].c = c;
	edge[ep].next = head[u];
	head[u] = ep ++;
	
	edge[ep].u = v;			// 建立反向边
	edge[ep].v = u;
	edge[ep].w = -w;
	edge[ep].c = 0;
	edge[ep].next = head[v];
	head[v] = ep ++;
}

bool SPFA(int src, int des)					// 根据流量求最小代价
{
	queue<int>q;
	memset(vis, 0, sizeof(vis));
	memset(pre, -1, sizeof(pre));
	for(int j = 0; j <= des; j ++){
		min_weight[j] = INF;
	}

	q.push(src);
	vis[src] = 1;
	min_weight[src] = 0;

	while(!q.empty()){
		int cur = q.front();
		vis[cur] = 0;
		q.pop();

		for(int i = head[cur]; i != -1; i = edge[i].next){
			int v = edge[i].v;
			if(edge[i].c > 0 && min_weight[cur] + edge[i].w < min_weight[v]){			// 必须有流量,并且代价更小
				min_weight[v] = min_weight[cur] + edge[i].w;
				pre[v] = i;
				if(!vis[v]){
					vis[v] = 1;
					q.push(v);
				}
			}
		}
	}

	if(min_weight[des] == INF)
		return 0;
	else
		return 1;
}

int MCMF(int src, int des)			// EK 最大流
{
	int ans = 0;
	while(SPFA(src, des)){
		int i, min_c = INF;		   // 最小流量
/*		for(i = des; i != src; i = edge[pre[i]].u){
			if(min_c > edge[pre[i]].c){
				min_c = edge[pre[i]].c;
			}
		}		*/
		min_c = 1;					// 此题最小流量一定是1

		ans += min_weight[des] * min_c;

		for(i = des; i != src; i = edge[pre[i]].u){
			edge[ pre[i] ].c -= min_c;
			edge[ pre[i]^1 ].c += min_c;		// 反向边与正向变是挨着的,所以此处异或即可
		}
	}

	return ans;
}

int main()
{
	char c;
	int i, j;
	int row, col;
	while(scanf("%d%d", &row, &col), row && col){
		int H_Num = 0, M_Num = 0;
		memset(head, -1, sizeof(head));		// 初始化临界表

		for(i = 0; i < row; i ++){
			for(j = 0; j < col; j ++){
				scanf(" %c", &c);
				if(c == 'H'){
					H_Num ++;
					H[H_Num].x = i;
					H[H_Num].y = j;
				}
				else if(c == 'm'){
					M_Num ++;
					M[M_Num].x = i;
					M[M_Num].y = j;
				}
			}
		}

		for(i = 1; i <= M_Num; i ++){		// 建图
			for(j = 1; j <= H_Num; j ++){
				int mh_min_weight = abs(M[i].x - H[j].x) + abs(M[i].y - H[j].y);
				AddEdge(i, M_Num + j, mh_min_weight, 1);
			}
		}

		int src = 0;						// 超级源点
		int des = M_Num + H_Num + 1;		// 超级汇点

		for(i = 1; i <= M_Num; i ++)		// 将超级源点和超级汇点加入到图
			AddEdge(src, i, 0, 1);
		for(i = M_Num + 1; i <= M_Num + H_Num; i ++)
			AddEdge(i, des, 0, 1);

		int ans = MCMF(src, des);
		printf("%d\n", ans);
	}

	return 0;
}

KM算法代码:

#include <stdio.h>
#include <string.h>
#include <math.h>
#define INF 0x7fffffff
#define N 120

struct Node{
	int x;
	int y;
};

int nx, ny;
int w[N][N];					// 保存权值
int lx[N], ly[N];				// 可行顶标
int pre[N], slack[N];			// 父节点,保存修改量
bool visx[N], visy[N];

bool DFS(int x)
{
	visx[x] = 1;
	for(int y = 0; y < ny; y ++){
		if(visy[y]){
			continue;
		}

		int t = lx[x] + ly[y] - w[x][y];
		if(t == 0){					// 相等子图
			visy[y] = 1;
			if(pre[y] == -1 || DFS(pre[y]) ){
				pre[y] = x;
				return 1;			// 找到增广路
			}
		}
		else if(slack[y] > t){		// 不在相等子图中slack 取最小的 
			slack[y] = t;
		}
	}

	return 0;						// 未找到增广路
}

int KM()
{
	int i, j;
	memset(pre, -1, sizeof(pre));
	memset(ly, 0, sizeof(ly));
	for(i = 0; i < nx; i ++){
		lx[i] = -INF;
		for(j = 1; j < ny; j ++){
			if(w[i][j] > lx[i]){
				lx[i] = w[i][j];
			}
		}
	}

	for(int x = 0; x < nx; x ++){
		for(i = 0; i < ny; i ++){
			slack[i] = INF;
		}

		while(1){
			memset(visx, 0, sizeof(visx));
			memset(visy, 0, sizeof(visy));

			if(DFS(x)){				// 找到增广路,为下一点增广,否则修改顶标
				break;
			}

			int d = INF;
			for(i = 0; i < ny; i ++){
				if(!visy[i] && d > slack[i])
					d = slack[i];
			}

			for(i = 0; i < nx; i ++){
				if(visx[i]){
					lx[i] -= d;
				}
			}

			for(i = 0; i < ny; i ++){
				if(visy[i]){
					ly[i] += d;
				}
				else{
					slack[i] -= d;		// 修改顶标后,要把所有不在交错树中的Y顶点的slack值都减去d  
				}
			}
		}
	}

	int ans = 0;
	for(i = 0; i < ny; i ++){
		if(pre[i] >= 0)
			ans += w[pre[i]][i];
	}

	return ans;
}

int main()
{
	char c;
	int x, y;
	Node H[N], M[N];
	while(scanf("%d%d", &x, &y), x && y){
		memset(w, 0, sizeof(w));
		nx = ny = 0;

		int i, j;
		for(i = 0; i < x; i ++){
			for(j = 0; j < y; j ++){
				scanf(" %c", &c);
				if(c == 'H'){
					H[nx].x = i;
					H[nx].y = j;
					nx ++;
				}
				else if(c == 'm'){
					M[ny].x = i;
					M[ny].y = j;
					ny ++;
				}
			}
		}

		int dis;
		for(i = 0; i < nx; i ++){				// 建图
			for(j = 0; j < ny; j ++){
				dis = abs(H[i].x - M[j].x) + abs(H[i].y - M[j].y);
				w[i][j] = - dis;
			}
		}

		int ans = KM();
		printf("%d\n", -ans);
	}

	return 0;
}


POJ 2195 二分图最小权匹配KM算法 本来是打算昨天晚上写的, 昨天网速渣的连优快云都进不去,没办法 只能现在来写了 先写写对KM算法的理解,KM算法是对每个点设置一个顶标,只有当边长等于两边点的顶标之和的时候才进行增广,这样就能保证得到的一定是最大权匹配。 如果找不到匹配的时候就对交替路中X集合的顶标减少一个d Y集合的顶标增加一个d。 这样两个点都在交替路中的时候x[i]+y[i]的和不边 X在 Y不在的时候x[ 阅读详情

相关推荐

二分图的最大权匹配(最小权匹配)KM算法

如果二分图的每条边都有的一个权值,如何求出权值和最大(最小)

ZT在努力 2106

POJ 3686 —— 最小费用流||最小费用匹配&KM

The Windy's Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 3520   Accepted: 1509 Description The Windy's is a world famous toy factory that owns M top-class

XMzhou的专栏 1173

利用腾讯云轻量服务器快速搭建网站CDN

腾讯云的轻量最近在主机和站长中间可谓是占尽来风头,优秀的线路,低廉的价格使得越来越多的人开始使用腾讯云的轻量级服务器来部署应用。由于腾讯云轻量服务器的海外服务器电信走的是CN2GIA线路带宽30m挺适合做CDN的,我就记录一下如何利用腾讯云香港的轻量服务器搭建一个CDN。 购买服务器 首先选购服务器,最近腾讯云在做活动,力度很大国内备案用户可以选用国内的服务器最低128元/年,未备案的可以选用香港或者新加坡的服务器。 购买链接 服务器系统选Debian、Ubuntu、centos都可以 一键脚

demo_top的博客 2565

POJ - 2195 (二分最小权匹配 && 最小费用最大流)

题目连接 题意: 图上,N个小矮人,N个房子,每个单位时间内 每个小矮人都能水平或者垂直移动一个单位步长到相邻的点。 每次移动消费1块钱,直到他进入房屋,每个房子只能容纳一个小矮人 问支付最低的金额。将这N个小矮人送入这N个不同的房间 ...

Harington的博客 481

Hypermesh静力学仿真分析与模态分析-02

hypermesh中对较复杂实体进行静力学分析和模态分析,包含材料属性添加,载荷设置等等

Look_forward_的博客 6776

全面分析总结解决Could not transfer artifact org.apache.maven.plugins等此类问题的方法

全面分析总结解决Could not transfer artifact org.apache.maven.plugins,Could not transfer artifact xxx from/to xxx等此类问题的方法

ccjjjjdff的博客 1万+

POJ 2195 Going Home 最小费用最大流 or KM算法

题目大意是一张地图中,有n个人要走回n个房子里,然后人只能横着或竖着走一格,求他们回家的距离总和最短。 这道题看起来是个最优匹配问题,用KM或者最小费用最大流做 首先把每个人与每个房子之间的距离求出来 然后就是套用模板了 #include &lt;iostream&gt; #include &lt;vector&gt; #include &lt;list&gt; #include &l...

java开发指南博客 【转载】 176

Silvaco TCAD仿真例库——肖特基二极管正向特性(例子)

此示例演示了肖特基二极管正向特性的仿真。 展示了: 使用 Atlas 语法形成二极管结构 设置阳极的肖特基势垒高度 正向偏置阳极 代码 第一部分:描述设备 mesh(网格) electrodes locations(电极位置) doping distribution(掺杂分布) 这是位于结构左侧和右侧的,2维n型器件,具有重掺杂浮动 p 型保护环区域, (2D n-type device with heavily doped floating p-type guard ring regio.

weixin_41788560的博客 2万+

二分图匹配(最小费用完美匹配) poj 2195 GoingHome

Going HomeTime Limit: 1000MS Memory Limit: 65536KTotal Submissions: 9224 Accepted: 4752DescriptionOn 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 adjac

likaihua1989的专栏 1418

Blender SMPL-X 插件安装

Blender XMPL-X 插件安装

heleneveryday的专栏 5358

【OpenClaw从入门到精通】第17篇:OpenClaw巨头布局实战:阿里CoPaw/腾讯云/百度/火山引擎深度拆解(2026实操版)

2026年OpenClaw以22.8万星标登顶GitHub,引发阿里、腾讯、百度、字节等互联网巨头入局角逐。本文基于公开技术文档与实测经验,深度解析四大巨头的OpenClaw布局战略:阿里云CoPaw的全栈托管、腾讯云的流量入口绑定、百度智能云的搜索生态内嵌、火山引擎的极致智力供给。从核心原理、算法构建、实操流程三个维度,提供可直接落地的接入方案,包含完整代码示例与执行结果验证。通过流程图可视化核心架构,搭配避坑指南与选型矩阵,帮助新手快速上手、进阶读者实现多厂商协同部署。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1682

二分图最大匹配:匈牙利(Hungary)算法

基本概念 二分图:二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图 匹配:在图论中,匹配是指寻找图中没有任何两条边拥有一个共同顶点的子图 最大匹配:一个图所有匹配中,所含匹配边数最多的匹配 利用匈牙利算法可以得到二分图的最大匹配 参考:1.匈牙利算法与增广路径 2.匈牙利算法 代码实现: public

qq_43635212的博客 399

[Research Tips] 我的zotero文献管理方案: 云端同步+iPad批注+overleaf笔记

文献管理一直是一个很头疼的事. 最初直接在paper上做笔记, 后来尝试各种各样的文献管理软件, 比如endnote, mendeley等, 再后来直接用excel. 每一种方案都不是很满意. 最近尝试了各种软件, 摸索出一个合适自己的文献管理方案, 分享给大家. 我的需求: 支持PDF内全文搜索. 支持笔记搜索. 支持同步 可以批注PDF. 支持word内引用 支持Tex笔记语法 支持标签化管理 目前的方案除了第二个需求, 其他的都支持. 就目前我的经验来说, 除了知网研学可以搜索笔记外, 其他软件都

落日之城 5316

POJ 2195 Going Home【KM算法-二分图的最优匹配】

 Going HomeTime Limit: 1000MS Memory Limit: 65536KTotal Submissions: 8380 Accepted: 4324DescriptionOn 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

bobten2008的专栏 1715

SpringBoot实战教程-springboot概论

Spring Boot 是一个快速开发框架,能够快速的整合第三方框架,简化XML配置,全部采用注解形式,以及自动配置。内置web容器,帮助开发者能够实现快速开发,简化了应用系统的初始搭建以及开发过程。

鸟哥哥的专栏 4155

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

poj 2195 Going Home (KM算法)

呃,省赛已经过去了,生活应该继续~~ 好几天没写博了,一直在研究KM算法,今天算是有点小明白了,做了一道模板题练练手。 先讲讲我理解的KM算法吧,如果你已经学会二分匹配中的匈牙利算法,那么要理解KM算法就很容易了,其实KM算法就是在匈牙利算法的基础上加上两点的权值。 首先是相等子图的概念:设顶点Xi的顶标为A[ i ],顶点Yj的顶标为B[ j ],顶点Xi与Yj之间的边权为w...

B218707的博客 199

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

poj 2195 KM算法(完备匹配)

题目链接:http://poj.org/problem?id=2195题目大意:在n*m的矩阵中,有一些man和house,数目相等,要使每个man都回到一个house里,所走的距离为对应位置的行号差和列号差之和,求所需走的最小距离并输出思路:很明显是二分图最小权值匹配问题,由于KM算法求的是最大权值匹配,故要将权值取负,然后用KM模板即可,最后结果再取反输出对于KM算法,我还是处于懵懂状态,需要继续理解#include #include #include #define N 110 #define

Acceptyly的专栏 877

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

HDU 1533 && poj 2195 Going Home KM算法

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

弱智就要多努力 560

HDU 2255 奔小康赚大钱 POJ 2195 Going Home 最大权完美匹配 KM算法

两道KM算法模板题 可以作为求最大完美匹配模板 一个是求最大权,一个求最小权 ,最小权可以将所有的边权取相反数,求得最大权之后再取反。 HDU 2255代码: /*--------------------- #headfile--------------------*/ #include #include #include #include #include #include #

__ElemenT 547

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

题目链接:点击查看 题目大意:给出一个n*m的地图,现在有一定数量的小人要回到屋子里去,题目保证图中的小人和屋子的数量是一致的,小人回到小屋的距离是两个点坐标的曼哈顿距离,每个小屋只能容纳一个小人,现在要让所有小人都回到屋子,问怎样设计能让总的距离之和最小 题目分析:因为KM算法是在完备匹配中求最大权匹配的,但这个题目让求的是完备匹配下的最小权匹配,有一个方法可以利用KM算法,就是建立负边,这...

Falcon的博客 468

避坑指南:Windows/Linux下MinIO密码忘了或要修改?三种方法教你搞定

本文详细介绍了在Windows和Linux环境下重置或修改MinIO密码的三种实用方法,包括环境变量临时覆盖法、服务配置永久修改法和数据目录重置法。针对不同运维场景提供安全可靠的解决方案,帮助用户有效管理MinIO密码,确保服务连续性和数据安全。

weixin_30596165的博客 462

POJ 2195 Going Home(KM)- from lanshui_Yang

题目大意:一张图中,有相等数量的“m” 和 “H” ,分别代表人和房子,要求通过移动人使最终每个房子里都有一个人,输出最小的移动步数。         解题思路:这题是求最小权值匹配,可用KM算法求解,需要注意的是,KM算法求的是最大权值匹配,这里需要把每条边的权值取反,得到最大权值匹配后,再把答案取反。         请看代码: #include #include #incl

lanshui_Yang的专栏 1116

POJ 2195 Going Home(最小权匹配、KM算法)

题目链接: POJ 2195 Going Home 题意: 给出一个r*c的矩阵,字母H代表房屋,字母m代表客人,房屋的数量和客人的数量相同。每间房只能住一个人。求这些客人全部住进客房的最少移动步数?#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <string> #incl

ramay7 570

POJ 2195 Going Home (二分图最大权匹配、KM算法)

题意:给你一张图,图上有n个人和n座房子,每个人需要回到一所房子,要求路程之和最小。 ...H.... ...H.... ...H.... mmmHmmmm ...H.... ...H.... ...H.... 题解:其实题目是求最小带权匹配,怎么化成求最大带权匹配呢?方法一可以将每个值取相反数。方法二用上界减去各个值。 基本原理   该算法是通过给每个顶点一个标号(叫做顶

1529

POJ2195 Going Home (最小费最大流||二分图最大权匹配)

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

Jelly_acm的博客 1243

poj2195——Going Home

<br />最小权值匹配,跟最大权值匹配差不多,但有些地方需改变:<br />1:t=gg[u][v]-lx[u]-ly[v];<br />2:for(i=0;i<topx;i++) { min=1000; for(j=0;j<topy;j++) if(gg[i][j]<min)min=gg[i][j]; lx[i]=min; }<br />3:for(j=0;j<topx;j++) if(vx[j]) lx[j]+=d; for(j=0;j<topy;j++

r_ax的专栏 490
上一篇: nyoj-116 士兵杀敌(二)(树状数组插点问线-模板题)
下一篇: nyoj-109 数列转换 (守恒定律)
tbl00c
博客等级 码龄13年 21粉丝 91原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值