UVA 10888 km 题库61页

 注意求最小值的方法。

const  int  maxn = 108 ;
int    lx[maxn] , ly[maxn] ;
int    Left[maxn] ;
int    w[maxn][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] && lx[i] + ly[j] == w[i][j]){
                  T[j] = 1 ;
                  if(!Left[j] || match(Left[j])){
                       Left[j] = i ;
                       return 1 ;
                  }
            }
       }
       return 0 ;
}

void   update(){
       int 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  ;
}

char  g[48][48]  ;

int   N , M  ;
int   can(int x , int y){
      return 1 <= x && x <= N && 1 <= y && y <= M ;
}

int   d[4][2] = {{-1,0},{0,-1},{1,0},{0,1}} ;
int   dist[48][48] ;
bool  in[48][48]  ;
vector<pair<int , int> > lisx , lisb ;

void  bfs(int sx , int sy , int id){
      queue< pair<int ,int> > q ;
      q.push(make_pair(sx,sy)) ;
      memset(dist , 63 , sizeof(dist)) ;
      dist[sx][sy] = 0  ;
      in[sx][sy] = 1 ;
      while(! q.empty()){
            pair<int , int> now = q.front() ;
            q.pop() ;
            in[now.first][now.second] = 0 ;
            for(int i = 0 ; i < 4 ; i++){
                 int x = now.first + d[i][0]  ;
                 int y = now.second + d[i][1] ;
                 if(! can(x , y) || g[x][y] == '#') continue ;
                 if(dist[x][y] > dist[now.first][now.second] + 1){
                       dist[x][y] = dist[now.first][now.second] + 1 ;
                       if(!in[x][y]){
                            in[x][y] = 1 ;
                            q.push(make_pair(x , y)) ;
                        }
                 }
            }
      }
      for(int i = 0 ; i < lisb.size() ; i++){
           w[id][i+1] = min(w[id][i+1] , dist[lisb[i].first][lisb[i].second]) ;
      }
}

int  main(){
     int t , i , j , b , x ;
     cin>>t ;
     while(t--){
          cin>>N>>M ;
          for(i = 1 ; i <= N ; i++) scanf("%s" , g[i]+1) ;
          lisx.clear() ;
          lisb.clear() ;
          for(i = 1 ; i <= N ; i++){
              for(j = 1 ; j <= M ; j++){
                  if(g[i][j] == 'B')
                        lisb.push_back(make_pair(i , j)) ;
                  else if(g[i][j] == 'X')
                        lisx.push_back(make_pair(i , j)) ;
              }
          }
          n = lisb.size() ;
          memset(w , 63 , sizeof(w)) ;
          for(i = 0 ; i < lisx.size() ; i++){
               bfs(lisx[i].first , lisx[i].second , i+1) ;
          }
          for(i = 1 ; i <= n ; i++)
             for(j = 1 ; j <= n ; j++){
                    w[i][j] = -w[i][j] ;
             }
          cout<< -km() << endl  ;
     }
     return  0 ;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值