hdu 1533(最小权匹配)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1533

题意:

给你一个N行M列的矩阵,其中“.”代表空地,“H”代表房子,“m”代表人,其中有n个房子和n个人。现在要求每个人进入一间房子,且人走一步需要支付1美元。

求最小需要花费多少美元才能让所有人都进入到房子中(每个人只能进入一间房子,每个房子只能容纳一个人)。

思路:就是一个二分图最优匹配的变形,所以说建图很重要啊!!!(把‘m'的坐标计入到X集,’H‘的坐标计入到Y集)在建图的时候,将每条边的权值变为负数。然后lx[i]初始化为-inf,结果输出-ans,就可以得到最小权值

View Code
  1 #include<iostream>
  2 const int MAXN=110;
  3 const int inf=1<<30;
  4 using namespace std;
  5 char G[MAXN][MAXN];
  6 int map[MAXN][MAXN];
  7 int lx[MAXN],ly[MAXN];
  8 int match[MAXN];
  9 bool visitx[MAXN],visity[MAXN];
 10 int n;
 11 
 12 int Hungary(int u){
 13     visitx[u]=true;
 14     for(int i=0;i<n;i++){
 15         if(!visity[i]&&lx[u]+ly[i]==map[u][i]){
 16             visity[i]=true;
 17             if(match[i]==-1||Hungary(match[i])){
 18                 match[i]=u;
 19                 return true;
 20             }
 21         }
 22     }
 23     return false;
 24 }
 25 
 26 void KM_prefect_match(){
 27     int tmp;
 28     //注意,此时要初始化为无穷小
 29     for(int i=0;i<n;i++){
 30         lx[i]=-inf;
 31     }
 32     memset(ly,0,sizeof(ly));
 33     for(int i=0;i<n;i++){
 34         for(int j=0;j<n;j++){
 35             lx[i]=max(lx[i],map[i][j]);
 36         }
 37     }
 38     for(int i=0;i<n;i++)
 39     {
 40         while(1){
 41             memset(visitx,false,sizeof(visitx));
 42             memset(visity,false,sizeof(visity));
 43             if(Hungary(i))//匹配成功
 44                 break;
 45             else {
 46                 tmp=inf;
 47                 for(int j=0;j<n;j++)if(visitx[j]){//x在交错树中
 48                     for(int k=0;k<n;k++){
 49                         //y在交错树外
 50                         if(!visity[k]&&tmp>lx[j]+ly[k]-map[j][k]){
 51                             tmp=lx[j]+ly[k]-map[j][k];
 52                         }
 53                     }
 54                 }
 55                 //更新顶标
 56                 for(int j=0;j<n;j++){
 57                     if(visitx[j])
 58                         lx[j]-=tmp;
 59                     if(visity[j])
 60                         ly[j]+=tmp;
 61                 }
 62             }
 63         }
 64     }
 65 }
 66 
 67 int main(){
 68     int row,col;
 69     while(~scanf("%d%d",&row,&col)){
 70         if(row==0&&col==0)break;
 71         n=0;
 72         int cnt1=0,cnt2=0;
 73         memset(map,0,sizeof(map));
 74         memset(match,-1,sizeof(match));
 75         for(int i=0;i<row;i++){
 76             scanf("%s",G[i]);
 77             for(int j=0;j<col;j++){
 78                 if(G[i][j]=='m')n++;
 79             }
 80         }
 81         //建图很重要!!!
 82         for(int i=0;i<row;i++){
 83             for(int j=0;j<col;j++){
 84                 if(G[i][j]=='m'){
 85                     for(int k=0;k<row;k++){
 86                         for(int l=0;l<col;l++){
 87                             if(G[k][l]=='H'){
 88                                 map[cnt1][cnt2++]=-1*(abs(i-k)+abs(j-l));//由于求得是最小权值和,取相反数
 89                             }
 90                         }
 91                     }
 92                     cnt1++;
 93                     cnt2=0;
 94                 }
 95             }
 96         }
 97         KM_prefect_match();
 98         int ans=0;
 99         for(int i=0;i<n;i++){
100             ans+=map[match[i]][i];
101         }
102         printf("%d\n",-ans);//最后取相反数就行了
103     }
104     return 0;
105 }
原文地址:https://www.cnblogs.com/wally/p/2996177.html