zoukankan      html  css  js  c++  java
  • BZOJ1189 [HNOI2007]紧急疏散evacuate 【二分 + 网络流】

    题目

    发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域。每个格子如果是'.',那么表示这是一
    块空地;如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以从这儿撤出房间。已知门
    一定在房间的边界上,并且边界上不会有空地。最初,每块空地上都有一个人,在疏散的时候,每一秒钟每个人都
    可以向上下左右四个方向移动一格,当然他也可以站着不动。疏散开始后,每块空地上就没有人数限制了(也就是
    说每块空地可以同时站无数个人)。但是,由于门很窄,每一秒钟只能有一个人移动到门的位置,一旦移动到门的
    位置,就表示他已经安全撤离了。现在的问题是:如果希望所有的人安全撤离,最短需要多少时间?或者告知根本
    不可能。

    输入格式

    第一行是由空格隔开的一对正整数N与M,3<=N <=20,3<=M<=20,
    以下N行M列描述一个N M的矩阵。其中的元素可为字符'.'、'X'和'D',且字符间无空格。

    输出格式

    只有一个整数K,表示让所有人安全撤离的最短时间,
    如果不可能撤离,那么输出'impossible'(不包括引号)。

    输入样例

    5 5

    XXXXX

    X...D

    XX.XX

    X..XX

    XXDXX

    输出样例

    3

    题解

    先bfs预处理每个点到各个出口的最短距离
    二分一下时间(t),对出口拆点表示各个时间的出口
    每个人向每个出口大于最短路的那些点连边

    然后网络流判一下能否完全匹配即可

    【坑点:角落的出口无法到达】

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    using namespace std;
    const int maxn = 300005,maxm = 6000005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    char s[25][25];
    int N,M,vis[25][25],id[25][25],now,X[] = {0,0,-1,1},Y[] = {-1,1,0,0};
    int n,m,dis[405][405],flag,S,T;
    int h[maxn],ne = 2;
    struct EDGE{int to,nxt,f;}ed[maxm];
    inline void build(int u,int v,int f){
    	ed[ne] = (EDGE){v,h[u],f}; h[u] = ne++;
    	ed[ne] = (EDGE){u,h[v],0}; h[v] = ne++;
    }
    struct point{int x,y,d;};
    void bfs(int x,int y){
    	memset(vis,0,sizeof(vis));
    	queue<point> q; q.push((point){x,y,0});
    	point u; int nx,ny;
    	while (!q.empty()){
    		u = q.front(); q.pop();
    		for (int k = 0; k < 4; k++){
    			nx = u.x + X[k];
    			ny = u.y + Y[k];
    			if (nx < 1 || ny < 1 || nx > N || ny > M || s[nx][ny] == 'X' || vis[nx][ny])
    				continue;
    			vis[nx][ny] = true;
    			if (s[nx][ny] == 'D') dis[id[x][y]][id[nx][ny]] = u.d + 1,flag = true;
    			else q.push((point){nx,ny,u.d + 1});
    		}
    	}
    }
    int q[maxn],head,tail;
    int d[maxn],Vis[maxn],cur[maxn];
    bool bfs(){
    	for (int i = S; i <= T; i++) d[i] = Vis[i] = 0;
    	q[head = tail = 1] = S; Vis[S] = true;
    	int u;
    	while (head <= tail){
    		u = q[head++];
    		Redge(u) if (ed[k].f && !Vis[to = ed[k].to]){
    			d[to] = d[u] + 1; Vis[to] = true;
    			if (to == T) return true;
    			q[++tail] = to;
    		}
    	}
    	return Vis[T];
    }
    int dfs(int u,int minf){
    	if (u == T || !minf) return minf;
    	int flow = 0,f,to;
    	if (cur[u] == -1) cur[u] = h[u];
    	for (int& k = cur[u]; k; k = ed[k].nxt)
    		if (d[to = ed[k].to] == d[u] + 1 && (f = dfs(to,min(minf,ed[k].f)))){
    			ed[k].f -= f; ed[k ^ 1].f += f;
    			flow += f; minf -= f;
    			if (!minf) break;
    		}
    	return flow;
    }
    int maxflow(){
    	int flow = 0;
    	while (bfs()){
    		for (int i = S; i <= T; i++) cur[i] = -1;
    		flow += dfs(S,INF);
    	}
    	return flow;
    }
    bool check(int len){
    	memset(h,0,sizeof(h));
    	ne = 2; S = 0; T = n + m * len + 1;
    	REP(i,n){
    		build(S,i,1);
    		REP(j,m){
    			for (int k = dis[i][j]; k <= len; k++)
    				build(i,n + (j - 1) * len + k,1);
    		}
    	}
    	REP(i,m) REP(j,len) build(n + (i - 1) * len + j,T,1);
    	int t = maxflow();
    	return t == n;
    }
    int main(){
    	N = read(); M = read();
    	REP(i,N){
    		scanf("%s",s[i] + 1);
    		REP(j,M){
    			if (s[i][j] == '.') id[i][j] = ++n;
    			if (s[i][j] == 'D') id[i][j] = ++m;
    		}
    	}
    	REP(i,n) REP(j,m) dis[i][j] = INF;
    	REP(i,N) REP(j,M){
    		if (s[i][j] == '.'){
    			flag = false;
    			bfs(i,j);
    			if (!flag) {
    				puts("impossible");
    				return 0;
    			}
    		}
    	}
    	int l = 0,r = 500,mid;
    	while (l < r){
    		mid = l + r >> 1;
    		if (check(mid)) r = mid;
    		else l = mid + 1;
    	}
    	printf("%d
    ",l);
    	return 0;
    }
    
    
  • 相关阅读:
    SpringBoot到底run了什么
    Activity生命周期
    Activities and Tasks
    Android开发指南中文版(二)Application Fundamentals
    Android开发指南中文版(三)Intents and Intent Filters
    Android开发指南中文版(一)What is Android?
    Activity的启动模式
    skydrive 中 文件夹以zip格式下载,含有中文的文件将会被改名
    装了7个虚拟机
    google reader 居然要关闭了?
  • 原文地址:https://www.cnblogs.com/Mychael/p/8918542.html
Copyright © 2011-2022 走看看