POJ 3565 KM算法 题库221

KM算法挺好的, 《训练手册》349页上讲解很详细。


const  int  maxn =  108 ;
double   w[maxn][maxn] ;
double   lx[maxn] , ly[maxn] ;
int   Left[maxn] ;
bool  S[maxn] , T[maxn] ;
int   n ;

bool  match(int i){
      S[i] = 1 ;
      for(int j = 1  ; j <= n ; j++){
          if(!T[j] && fabs( lx[i] + ly[j] - w[i][j] ) < 1e-6){
               T[j] = 1 ;
               if(! Left[j] || match(Left[j]) ){
                     Left[j] = i ;
                     return 1 ;
               }
          }
      }
      return  0 ;
}

void  update(){
      double a = 1<<30 ;
      for(int i = 1 ; i <= n ; i++){
          if(S[i]){
              for(int j = 1 ; j <= n ; j++){
                  if(! T[j])
                      a = min(a , lx[i] + ly[j] - w[i][j]) ;
              }
          }
      }
      for(int i = 1 ; i <= n ; i++){
          if(S[i])  lx[i] -= a ;
          if(T[i])  ly[i] += a ;
      }
}

int  km(){
     for(int i = 1 ; i <= n ; i++){
         Left[i] = lx[i] = ly[i] = 0 ;
         for(int j = 1 ; j <= n ; j++)
             lx[i] = max(lx[i] , w[i][j]) ;
     }
     for(int i = 1 ; i <= n ; i++){
          while(1){
               for(int j = 1 ; j <= n ; j++)
                   S[j] = T[j] = 0 ;
               if(match(i))  break ;
               else   update() ;
          }
      }
      int s = 0 ;
      for(int i = 1 ; i <= n ; i++) s += w[Left[i]][i] ;
      return s ;
}

int  ax[maxn] , ay[maxn]  ;
int  bx[maxn] , by[maxn]  ;
int  ans[maxn] ;

int  main(){
     int i , j  ;
     cin>>n  ;
     for(i = 1  ; i <= n ; i++) scanf("%d%d" ,&ax[i] , &ay[i]) ;
     for(i = 1  ; i <= n ; i++) scanf("%d%d" ,&bx[i] , &by[i]) ;
     for(i = 1  ; i <= n ; i++){
         for(j = 1 ; j <= n ; j++)
            w[i][j] = -sqrt(0.0 + (ax[i] - bx[j])*(ax[i] - bx[j]) + (ay[i] - by[j])*(ay[i] - by[j]) );
     }
     km() ;
     for(i = 1 ; i <= n ; i++)  ans[Left[i]] = i ;
     for(i = 1 ; i <= n ; i++)  printf("%d\n" , ans[i]) ;
     return  0 ;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值