poj_2195_KM

题目描述:
   给一个矩阵,m表示人,h表示房子。.表示空地。人和房子数相等。求让所有的人进入不同的房子内,问最少走多少步?

解题思路:
   KM算法——求最佳匹配的。该题求最佳匹配 = 权值最小匹配。构图——二分图,把人道房子距离乘以-1,就转变为求最大权值匹配。两个函数:一个求完备匹配的匈牙利函数,一个更新可行顶标-执行求完备匹配的函数。(注意写的时候要细心。。一个条件忘了改wa了大半天)


代码:

#include <stdio.h>
#include <stdlib.h>
#define N 202

typedef struct{
   int x;
   int y;
}Pos;

int map[N][N], m_cnt, h_cnt, n, M;
char input[N][N];
Pos m[N], H[N];

int lx[N], ly[N], sx[N], sy[N], visit[N], link[N];

int dfs(int v){
   int i;
   sx[v] = 1;
   for(i=1;i<=h_cnt;i++){
      if(!sy[i] && lx[v] + ly[i] == map[v][i]){
         sy[i] = 1;
         if(link[i] == -1 || dfs(link[i])){
            link[i] = v;
            return 1;
         }
      }
   }
   return 0;
}

int km(){
   int i,j,k,min,sum;
   for(i=1;i<=m_cnt;i++){
      lx[i] = -40004;
      ly[i] = 0;
      for(j=1;j<=h_cnt;j++)
         if(lx[i] < map[i][j])
            lx[i] = map[i][j];
      link[i] = -1;
   }
   for(i=1;i<=h_cnt;i++){
      while(1){
          memset(sx,0,sizeof(sx));
          memset(sy,0,sizeof(sy));
          if(dfs(i))
             break;
          //update
          min = 10000;
          for(j=1;j<=m_cnt;j++)
             if(sx[j])
                for(k=1;k<=h_cnt;k++)
                   if(!sy[k])
                      if( lx[j] + ly[k] - map[j][k] < min)
                         min = lx[j] + ly[k] - map[j][k];

          for(j=1;j<=m_cnt;j++){
             if(sx[j])
                lx[j] -= min;
           
          }
          for(j=1;j<=h_cnt;j++){
              if(sy[j])
                ly[j] += min;
          }
      }
   }
   sum = 0;
   for(j=1;j<=h_cnt;j++){
     if(link[j]!=-1)
        sum += map[link[j]][j]; //lx[j] + ly[j]
   }
   return sum;
}

main(){
   int i,j;
  
   scanf("%d %d",&n, &M);
   while(n!=0){
       m_cnt = 0;
       h_cnt = 0;
       for(i=1;i<=n;i++){
          scanf("%s",input[i]);
          for(j=0;j<M;j++){
             if(input[i][j] == 'm'){
                 m_cnt ++;
                 m[m_cnt].x = i;
                 m[m_cnt].y = j;
             }
             else if(input[i][j]=="H"){
                h_cnt ++;
                H[h_cnt].x = i;
                H[h_cnt].y = j;
             }
          }
       }
        //构建二分图   
        for(i=1;i<=m_cnt;i++)
           for(j=1;j<=h_cnt;j++){
              map[i][j] = -1*(abs(m[i].x - H[j].x)+abs(m[i].y - H[j].y));
           }
       
        printf("%d\n",-1*km());
        scanf("%d %d",&n, &M);
   }
   
   system("pause");
   return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值