POJ 3057




X集合   :二元组(时间,门)
Y集合   : 人

只需要按时间递增去找增广路 ,时间递增也就是点从0 ,1 ,2  , , , Td-1。 直到最大匹配数恰好等于人的个数也就是p。则结束。

#define X first
#define Y second
const int maxn = 13 ;
vector< pair<int,int> > door , man ;
int  dist[maxn][maxn][maxn][maxn] ;
char str[18][18] ;
int  d[4][2] = {{1,0} , {-1,0} , {0,1} , {0 ,-1}} ;
int  n , m ;
vector<int> g[21000] ;
int  match[maxn * maxn] ;
bool vis[maxn * maxn] ;
int  Yset ;

inline int  cango(int x  , int y){
       return 1 <= x && x <= n && 1 <= y && y <= m ;
}

void bfs(pair<int ,int> s){
     queue< pair<int ,int> > que ;
     que.push(s) ;
     dist[s.X][s.Y][s.X][s.Y] = 0 ;
     while(! que.empty()){
          pair<int ,int> now = que.front() ; que.pop() ;
          for(int i = 0 ; i < 4 ; i++){
                int x = now.X + d[i][0] ;
                int y = now.Y + d[i][1] ;
                if(cango(x , y) && str[x][y] == '.' && dist[s.X][s.Y][x][y] == -1){
                       dist[s.X][s.Y][x][y] = dist[s.X][s.Y][now.X][now.Y] + 1 ;
                       que.push(make_pair(x,y)) ;
                }
          }
     }
}

int   dfs(int u){
      for(vector<int>::iterator it = g[u].begin() ; it != g[u].end() ; it++){
             if(vis[*it]) continue ;
             vis[*it] = 1 ;
             if(match[*it] == -1 || dfs(match[*it])){
                   match[*it] = u  ;
                   return 1 ;
             }
      }
      return 0 ;
}

void  Answer(){
      int T = n * m ;
      int d = door.size() ;
      int p = man.size() ;
      if(p == 0){ puts("0") ; return  ;}
      int i , j  , k , s , u  , sum = 0 ;
      for(i = 0 ; i <= d*T ; i++) g[i].clear() ;
      for(i = 0 ; i < d ; i++){
          for(j = 0  ; j < p ; j++){
               if((s = dist[door[i].X][door[i].Y][man[j].X][man[j].Y]) >= 0){
                    for(k = s ; k <= T ; k++)
                        g[(k-1)*d + i].push_back(T*d + j) ;
               }
          }
      }
      memset(match , -1 , sizeof(match)) ;
      Yset = p
      for(u = 0 ; u < T*d ; u++){
            memset(vis , 0 , sizeof(vis)) ;
            if(dfs(u)){
                   if(++sum == p){
                        printf("%d\n" , u/d + 1) ;
                        return ;
                   }
            }
      }
      puts("impossible") ;
}

int  main(){
     int i , j , t ;
     cin>>t ;
     while(t--){
          cin>>n>>m ;
          for(i = 1 ; i <= n ; i++) scanf("%s" ,str[i]+1) ;
          memset(dist , -1 , sizeof(dist)) ;
          door.clear() ; man.clear() ;
          for(i = 1 ; i <= n ; i++){
               for(j = 1 ; j <= m ; j++){
                    if(str[i][j] == 'D'){
                           door.push_back(make_pair(i,j)) ;
                           bfs(make_pair(i,j)) ;
                    }
                    else if(str[i][j] == '.')
                           man.push_back(make_pair(i,j)) ;
               }
          }
          Answer()  ;
     }
     return 0 ;
}








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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值