HDU 1533 Going Home (最大权完美匹配)
<题目链接>
题目大意:
给你一张地图,地图上m代表人,H代表房子,现在所有人要走到房子内,且一个房子只能容纳一个人(人和房子的数量相同),人每移动一步,需要花1美元,问所有人走到房子中的最小花费。
解题分析:
一个人对应一个房子,并且人与房子之间的花费相当于权值,很明显的最大权完美匹配,直接套用KM算法即可。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 #define INF 0x3f3f3f3f 8 #define rep(i,s,t) for(int i=s;i<=t;i++) 9 #define mem(a,b) memset(a,b,sizeof(a)) 10 #define mp make_pair 11 #define fi first 12 #define se second 13 const int N = 110; 14 char str[110]; 15 typedef pair<int,int>pii; 16 int n,m,nx,ny; 17 int lx[N],ly[N]; 18 int linker[N],slack[N],visx[N],visy[N],w[N][N]; 19 pii locx[N],locy[N]; //记录二分图中x,y两部分所有点的坐标 20 inline int dis(pii tmp1,pii tmp2){ //计算两点之间的花费 21 return (abs(tmp1.fi-tmp2.fi)+abs(tmp1.se-tmp2.se)); 22 } 23 bool DFS(int x){ 24 visx[x]=1; 25 rep(y,1,ny){ 26 if(visy[y])continue; 27 int tmp=lx[x]+ly[y]-w[x][y]; 28 if(!tmp){ 29 visy[y]=1; 30 if(linker[y]==-1||DFS(linker[y])){ 31 linker[y]=x; 32 return true; 33 } 34 }else slack[y]=min(slack[y],tmp); 35 } 36 return false; 37 } 38 int KM(){ 39 mem(linker,-1);mem(ly,0); 40 rep(i,1,nx){ 41 lx[i]=-INF; 42 rep(j,1,ny)lx[i]=max(lx[i],w[i][j]); 43 } 44 rep(x,1,nx){ 45 rep(i,1,ny)slack[i]=INF; 46 while(true){ 47 mem(visx,0);mem(visy,0); 48 if(DFS(x))break; 49 int d=INF; 50 rep(i,1,ny)if(!visy[i])d=min(d,slack[i]); 51 rep(i,1,nx)if(visx[i])lx[i]-=d; 52 rep(i,1,ny) 53 if(visy[i])ly[i]+=d; 54 else slack[i]-=d; 55 } 56 } 57 int res=0; 58 rep(y,1,ny) 59 if(linker[y]!=-1) 60 res+=w[linker[y]][y]; 61 return res; 62 } 63 int main(){ 64 while(~scanf("%d%d",&n,&m),n||m){ 65 nx=ny=0; 66 rep(i,1,n){ 67 scanf("%s",str+1); 68 rep(j,1,m){ 69 if(str[j]=='m')locx[++nx]=mp(i,j); //存下x,y两部分坐标 70 if(str[j]=='H')locy[++ny]=mp(i,j); 71 } 72 } 73 rep(i,1,nx) rep(j,1,ny){ 74 w[i][j]=-dis(locx[i],locy[j]); //得到两点之间的最短距离,也就是人到对应的房子所需花的钱,因为最后要求最小花费,所以这里要先取反 75 } 76 printf("%d\n",(-1)*KM()); //得到最小花费 77 } 78 }
2018-11-18
作者:is_ok
出处:http://www.cnblogs.com/00isok/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。