zoukankan      html  css  js  c++  java
  • 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
    ",(-1)*KM());   //得到最小花费
    77     }
    78 }

    2018-11-18

  • 相关阅读:
    node异步转同步(循环)
    三级省市区PCASClass.js插件
    微信公众号基础总结(待更新)
    ES6详解
    webpack配置
    高性能 CSS3 动画
    github上传口令
    纯css3 实现3D轮播图
    优美的js代码,拿去玩~
    关于列举属性用点还是用【】
  • 原文地址:https://www.cnblogs.com/00isok/p/9977869.html
Copyright © 2011-2022 走看看