hdu 1733 最大流sap

给定一个矩阵,'.'表示空位,'X'表示人,'#'表示墙,'@'表示门,

每分钟每个位置至多只能站一个人,人不能穿越墙,人能从门中出去。

每个人每分钟只能上下左右移动一步,问最少需要多少时间让所有的人出去。

-----------------

//dinic TLE 

----------------

(1):把每个点按照天数拆成d个点。

(2):添加源汇点scr和sink。

(3):源点向第0天地图上人所在位置的点连一天容量为1的边。

(4):枚举时间Ti

如果当前枚举的天数为d,那么地图中每个位置第d-1天的点向四周和本身第d天的点(新添加的点)连一条容量为1 的边。

(5):每次枚举只需向残留网络里重新添加一些新的点和边。然后再从源点向汇点跑最大流。

(6):直到前Ti天的最大流总和=总人数时,Ti就是所有的最少天数。

const  int  inf = 1000000000 ;
const  int  maxn = 10000 , maxm = 500000 ;
struct Edge{
       int v , f ,next ;
       Edge(){}
       Edge(int _v , int _f , int _next):v(_v) ,f(_f),next(_next){}
};
int  sourse , meet ;
int  id ;
Edge e[maxm*2 + 10] ;
int  g[maxn + 10] ;

void  add(int u , int v , int f){
      e[++id] = Edge(v , f ,g[u]) ;
      g[u] = id ;
      e[++id] = Edge(u , 0 , g[v]) ;
      g[v] = id ;
}
int cur[maxn] , pre[maxn] , gap[maxn] , dis[maxn] ;

void Init(){
     memset(g , -1 , sizeof(g)) ;
     id = 1 ;
}

int Sap(int s,int t,int n){
	int ans = 0 , aug = inf;//aug表示增广路的流量
    int i , v , u = pre[s] = s;
    for(i = 0 ; i <= n ; i++){
		cur[i] = g[i];
		dis[i] = gap[i] = 0;
	}
    gap[s] = n;
	bool flag;
    while(dis[s] < n){
		flag = false;
		for(int &j=cur[u] ; j!=-1 ; j=e[j].next){ //&j
			v = e[j].v;
			if(e[j].f > 0 && dis[u] == dis[v] + 1){
				flag = true;//找到容许边
				aug = min(aug , e[j].f);
				pre[v] = u;
				u = v;
				if(u == t){
					ans += aug;
					while(u != s){
						u = pre[u];
						e[cur[u]].f -= aug;
						e[cur[u]^1].f += aug;//注意
					}
					aug = inf;
				}
				break;//找到一条就退出
			}
		}
		if(flag) continue;
		int mindis = n;
		for(i = g[u] ; i!=-1 ; i=e[i].next){
			v = e[i].v;
			if(e[i].f > 0 && dis[v] < mindis){
				mindis = dis[v];
				cur[u] = i;
			}
		}
		if((--gap[dis[u]]) == 0) break;
		gap[dis[u] = mindis+1]++;
		u = pre[u];
	}
    return ans;
}
//------------------------------//

int  n , m , nn ;
char str[30][30] ;
bool used[30][30] ;
int  d[4][2] = {{1,0} ,{-1,0} ,{0,1} ,{0 ,-1}} ;
int  can(int x , int y){
     return 1 <= x && x <= n && 1 <= y && y <= m ;
}

int  isok(int x , int y){
     used[x][y] = 1 ;
     if(str[x][y] == '@') return 1 ;
     for(int i = 0 ; i < 4 ; i++){
         int xx = x + d[i][0] ;
         int yy = y + d[i][1] ;
         if(! can(xx , yy)) continue ;
         if(str[xx][yy] != '#' && !used[xx][yy]){
              if(isok(xx , yy)) return 1 ;
         }
     }
     return 0 ;
}
int  summan ;
int  cannotgoout(){
     for(int i = 1 ; i <= n ; i++){
         for(int j = 1 ; j <= m ; j++){
             if(str[i][j] == 'X'){
                  summan++ ;
                  memset(used , 0 , sizeof(used)) ;
                  if(! isok(i , j)) return 1 ;
             }
         }
     }
     return 0 ;
}

int  greed(int t){
     int i , j , u , k , x ,  y  , v ;
     for(i = 1 ; i <= n ; i++){
        for(j = 1 ; j <= m ; j++){
            if(str[i][j] == '#') continue ;
            u = (t-1)*n*m + (i-1)*m + j + 2 ;
            add(u , u+n*m , 1) ;
            for(k = 0 ; k < 4 ; k++){
                 x = i + d[k][0] ;
                 y = j + d[k][1] ;
                 if(! can(x , y) ) continue ;
                 if(str[x][y] == '#') continue ;
                 v = t*n*m + (x-1)*m + y + 2 ;
                 add(u , v , 1) ;
            }
        }
     }
     for(i = 1 ; i <= n ; i++){
        for(j = 1 ; j <= m ; j++){
             u = t*n*m + (i-1)*m + j + 2 ;
             if(str[i][j] == '@') add(u , meet , 1) ;
        }
     }
     nn += n*m ;
     return Sap(sourse , meet , nn) ;
}

int  main(){
     int i , j  , u , v , sum  , t ;
     while(scanf("%d%d" , &n , &m) != EOF){
          for(i = 1 ; i <= n ; i++)  scanf("%s" , str[i]+1) ;
          summan = 0 ;
          if(cannotgoout()){
               puts("-1") ;
               continue  ;
          }
          if(summan == 0){
               puts("0")  ;
               continue  ;
          }
          Init() ;
          sourse = 1 ; meet = 2 ;
          for(i = 1 ; i <= n ; i++){
              for(j = 1 ; j <= m ; j++){
                  u = (i-1)*m + j + 2 ;
                  if(str[i][j] == 'X') add(sourse , u , 1) ;
              }
          }
          nn = 2 + n*m ;
          sum = 0 ;
          t = 0 ;
          while(sum != summan){
               t++ ;
               sum += greed(t) ;
          }
          printf("%d\n" , t) ;
     }
     return 0 ;
}








你可能感兴趣的:(hdu 1733 最大流sap)