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

posted @ 2018-11-18 14:32  悠悠呦~  阅读(248)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end