二分图匹配入门专题1K - Going Home hdu1533km匹配
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二分图匹配入门专题1K - Going Home hdu1533km匹配相关的知识,希望对你有一定的参考价值。
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.
InputThere 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.
OutputFor 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 Out12
题意:输入一个n行m列的图,‘H’和‘m‘数目相等,从‘m’出发到‘H‘,走一步花费加1,问,在满足每个‘m‘都能走到‘H‘的情况下,求出
总的最小花费。
思路:求最小匹配,我们可以转换思路,用一个总的值sum-最大匹配,就是我们要求的最小匹配,比如说,我们要求一个集和中的
最小值min,那么我们用一个max减去集合中每一个数,再求出集合的最大值max2,我们所求的min = max-max2。
那么这道题中呢,只是把求最小值换为求最小和,我们同样可以用总和-最大和求得。(为什么让我想起了上次的最大子段和~~)
这个思路转换过来后,它就是一个km模板的套路题了。
~~~早起鸟儿果然有虫吃,又get到一个新技能,自己这道题一开始求得最大匹配,后来发现无法求出最小匹配,参考了大佬的博客才知道
可以建图的时候转换一下,不过最大的收获就是我的模板又得到了优化,之前是slack数组去存每一个不在交错树中的tmp值,最后还要
进行比较得出最小常数d,现在呢,就完全不用了,我们直接定义一个全局d,每次dfs的时候都更新一遍,就不用像之前那样处理
不在交错树中的slack值
#include<stdio.h> #include<string.h> #define N 110 #define INF 0x3f3f3f3f int n,m; char map[N][N]; int sumhome,summan; int w[N][N],linker[N]; int lx[N],ly[N],visx[N],visy[N]; int ans,d,nx,ny; struct node{ int x,y; }; node home[N],man[N]; int abs(int a)//取绝对值 { if( a < 0) return -a; return a; } void Count()//编号 { int i,j; sumhome = summan = 0; for(i = 1; i <= n; i ++) for(j = 1; j <= m; j ++) { if(map[i][j] == ‘H‘) { home[++sumhome].x = i; home[sumhome].y = j; } if(map[i][j] == ‘m‘) { man[++summan].x = i; man[summan].y = j; } } return; } void getmap()//建图 { int i,j; nx = summan; ny = sumhome; for(i = 1; i <= nx; i ++) for(j = 1; j <= ny; j ++) { w[i][j] = abs(man[i].x - home[j].x)+abs(man[i].y - home[j].y); } return; } int dfs(int x)//完全匹配 { int y,tmp; visx[x] = 1; for(y = 1; y <= ny; y ++) { if(!visy[y]) { tmp = lx[x] + ly[y] - w[x][y]; if(!tmp) { visy[y] = 1; if(linker[y] == -1||dfs(linker[y])) { linker[y] = x; return 1; } } else if(d > tmp)//取最小的不在增广轨中的常数d d = tmp; } } return 0; } int KM()//求最小匹配 { int sum,x,i,j; memset(linker,-1,sizeof(linker)); memset(ly,0,sizeof(ly)); for(i = 1; i <= nx; i ++) for(j = 1; j <= ny; j ++) w[i][j] = 100*100 - w[i][j];//极大值减去原来的值 for(i = 1; i <= nx; i ++) for(j = 1,lx[i] = -INF; j <= ny; j ++) if(lx[i] < w[i][j]) lx[i] = w[i][j];//初始化为权值最大的边的权值 for(x = 1; x <= nx; x++) { while(1) { d = INF;//常数d每次都要进行初始化 memset(visx,0,sizeof(visx));//每次dfs都要进行更新 memset(visy,0,sizeof(visy)); if(dfs(x)) break; for(i = 1; i <= nx; i ++) if(visx[i])//在增广轨中的x点标减去常数d lx[i] -= d; for(i = 1; i <= ny; i ++) if(visy[i])//在增广轨中的y点标加上常数d ly[i] += d; } } sum = 0; for(i = 1; i <= ny; i ++) if(linker[i]!=-1) sum += w[linker[i]][i]; sum = nx*100*100-sum;//总值-最大匹配,就是我们所求的最小匹配 return sum; } int main() { int i,j; while(scanf("%d%d",&n,&m),(m+n)!=0) { getchar(); for(i = 1; i <= n; i ++) scanf("%s",map[i]+1); Count();//对home,man进行编号 getmap();//得到带权值的图 ans = KM();//km算法 printf("%d\n",ans);//输出最小匹配 } return 0; }
以上是关于二分图匹配入门专题1K - Going Home hdu1533km匹配的主要内容,如果未能解决你的问题,请参考以下文章
[ACM] HDU 1533 Going Home (二分图最小权匹配,KM算法)
二分图匹配入门专题1H - Marriage Media light oj 1184二分图最大匹配
二分图匹配入门专题1F - COURSES poj1469最大匹配--匈牙利算法模板题