第一次做KM算法的题目,也许没能好好理解匈牙利算法,对这个KM算法几乎看不懂,上网搜了一下模板,这题几乎是抄的,看来要好好理解。
题意:给你一个地图,里面有人和有屋(测试数据可以看成是人数等于屋数),一个人只能想上下左右移动,求所有人移动的次数最少的情况下,所有人都能进入屋子,当然可以路过屋子而不进去。
解题思路:这题明显就是求最小权匹配的,只要把步数变为负数,就是求最大权匹配嘛,直接KM算法,模板过了,问题是建图要小心,注意好细节,这题其实不会很难的,KM算法要理解理解吖
31msG++代码
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
#include<cstdio>
using namespace std;
const int INF=1<<26;
typedef struct node{
 int x,y;
}node;

int n,m,numh,numm,ans;
int mj[105][105];
node pionth[105],piontm[105];
bool vx[105],vy[105];
int slack[105],match[105],lx[105],ly[105];

bool Find(int x)
{
 vx[x]=true;
 for(int j=1;j<=numm;j++)
 {
  if(vy[j]==false)
  {
   if(lx[x]+ly[j]==mj[x][j])
   {
    vy[j]=true;
       if(match[j]==-1||Find(match[j]))
       {
        match[j]=x;
        return true;
       }
   }
   else
    slack[j]=min(slack[j],lx[x]+ly[j]-mj[x][j]);
  }
 }
 return false;
}

void KM_match()
{
 int temp;
 for(int i=1;i<=numh;++i)//初始化为大负数
  lx[i]=-INF;
 memset(ly,0,sizeof(ly));
 for(int i=1;i<=numh;i++)
  for(int j=1;j<=numm;j++)
   lx[i]=max(lx[i],mj[i][j]);
 for(int i=1;i<=numh;i++)
 {
  for(int j=1;j<=numm;j++)
   slack[j]=INF;
  memset(vx, false, sizeof(vx));  
        memset(vy, false, sizeof(vy));
  while(!Find(i))
  {
    temp = INT_MAX;  
             for(int j=1;j<=numm;++j)  
                 if(!vy[j])  
                     temp = min(temp,slack[j]);  
             for(int j=1;j<=numm;++j)  
             {  
                 if(vx[j])  
                     lx[j]-=temp;  
                 if(vy[j])  
                     ly[j]+=temp;  
                 else  
                     slack[j]-=temp;  
              } 
        memset(vx, false, sizeof(vx));  
              memset(vy, false, sizeof(vy));
  }
 }
}

 


int main()
{
 int i,j;
 char ch;
 while(scanf("%d %d",&n,&m),n||m)
 {
  memset(match, -1, sizeof(match));  
  ans=numh=numm=0;
  for(i=0;i<n;i++)
  {
   getchar();
   for(j=0;j<m;j++)
   {
    ch=getchar();
    if(ch=='H')
    {
     numh++;
     pionth[numh].x=i;
     pionth[numh].y=j;
    }
    else if(ch=='m')
    {
     numm++;
     piontm[numm].x=i;
     piontm[numm].y=j;
    }
   }
  }//确定点
  for(i=1;i<=numh;i++)
  {
   for(j=1;j<=numm;j++)
   {
    int d=abs(pionth[i].x-piontm[j].x)+abs(pionth[i].y-piontm[j].y);
    mj[i][j]=0-d;
   }
  }//建图
  /*for(i=1;i<=numh;i++)
  {
   for(j=1;j<=numm;j++)
   {
    printf("%d ",mj[i][j]);
   }
   printf("\n");
  }*/
  KM_match();
  for(j=1;j<=numm;j++)
   ans+=mj[match[j]][j];
  printf("%d\n",0-ans);
 }

}