1189: [HNOI2007]紧急疏散evacuate
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1132 Solved: 412
[Submit][Status][Discuss]
Description
发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域。每个格子如果是'.',那么表示这是一块空地;如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以从这儿撤出房间。已知门一定在房间的边界上,并且边界上不会有空地。最初,每块空地上都有一个人,在疏散的时候,每一秒钟每个人都可以向上下左右四个方向移动一格,当然他也可以站着不动。疏散开始后,每块空地上就没有人数限制了(也就是说每块空地可以同时站无数个人)。但是,由于门很窄,每一秒钟只能有一个人移动到门的位置,一旦移动到门的位置,就表示他已经安全撤离了。现在的问题是:如果希望所有的人安全撤离,最短需要多少时间?或者告知根本不可能。
Input
输入文件第一行是由空格隔开的一对正整数N与M,3<=N <=20,3<=M<=20,以下N行M列描述一个N M的矩阵。其中的元素可为字符'.'、'X'和'D',且字符间无空格。
Output
只有一个整数K,表示让所有人安全撤离的最短时间,如果不可能撤离,那么输出'impossible'(不包括引号)。
Sample Input
5 5
XXXXX
X...D
XX.XX
X..XX
XXDXX
XXXXX
X...D
XX.XX
X..XX
XXDXX
Sample Output
3
题解:S-'.'-'D'-T;先从门bfs出每个‘.’点到门的距离,注意要每种情况都要计算所以开一个距离数组400*20*20+1,再二分时间为最后‘D’到T的容量;
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<queue> #include<cmath> #include<map> using namespace std ; typedef long long ll; inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } //****************************************************************** namespace NetFlow { const int MAXN=100000,MAXM=1000000,inf=1e9; struct Edge { int v,c,f,nx; Edge() {} Edge(int v,int c,int f,int nx):v(v),c(c),f(f),nx(nx) {} } E[MAXM]; int G[MAXN],cur[MAXN],pre[MAXN],dis[MAXN],gap[MAXN],N,sz; void init(int _n) { N=_n,sz=0; memset(G,-1,sizeof(G[0])*N); } void link(int u,int v,int c) { E[sz]=Edge(v,c,0,G[u]); G[u]=sz++; E[sz]=Edge(u,0,0,G[v]); G[v]=sz++; } int ISAP(int S,int T) {//S -> T int maxflow=0,aug=inf,flag=false,u,v; for (int i=0;i<N;++i)cur[i]=G[i],gap[i]=dis[i]=0; for (gap[S]=N,u=pre[S]=S;dis[S]<N;flag=false) { for (int &it=cur[u];~it;it=E[it].nx) { if (E[it].c>E[it].f&&dis[u]==dis[v=E[it].v]+1) { if (aug>E[it].c-E[it].f) aug=E[it].c-E[it].f; pre[v]=u,u=v; flag=true; if (u==T) { for (maxflow+=aug;u!=S;) { E[cur[u=pre[u]]].f+=aug; E[cur[u]^1].f-=aug; } aug=inf; } break; } } if (flag) continue; int mx=N; for (int it=G[u];~it;it=E[it].nx) { if (E[it].c>E[it].f&&dis[E[it].v]<mx) { mx=dis[E[it].v]; cur[u]=it; } } if ((--gap[dis[u]])==0) break; ++gap[dis[u]=mx+1]; u=pre[u]; } return maxflow; } bool bfs(int S,int T) { static int Q[MAXN]; memset(dis,-1,sizeof(dis[0])*N); dis[S]=0; Q[0]=S; for (int h=0,t=1,u,v,it;h<t;++h) { for (u=Q[h],it=G[u];~it;it=E[it].nx) { if (dis[v=E[it].v]==-1&&E[it].c>E[it].f) { dis[v]=dis[u]+1; Q[t++]=v; } } } return dis[T]!=-1; } int dfs(int u,int T,int low) { if (u==T) return low; int ret=0,tmp,v; for (int &it=cur[u];~it&&ret<low;it=E[it].nx) { if (dis[v=E[it].v]==dis[u]+1&&E[it].c>E[it].f) { if (tmp=dfs(v,T,min(low-ret,E[it].c-E[it].f))) { ret+=tmp; E[it].f+=tmp; E[it^1].f-=tmp; } } } if (!ret) dis[u]=-1; return ret; } int dinic(int S,int T) { int maxflow=0,tmp; while (bfs(S,T)) { memcpy(cur,G,sizeof(G[0])*N); while (tmp=dfs(S,T,inf)) maxflow+=tmp; } return maxflow; } } struct sss { int x,y,t; }hh[30][30]; int n,m; int ss[4][2]={-1,0,0,-1,1,0,0,1}; int tim[405][30][30]; char mp[30][30]; int tot; int cnt=0; int xxx[401],yyy[401]; void bfss(int a,int b,int index) { sss k,kk; queue<sss>q; k.x=a; k.y=b; k.t=0; q.push(k); while(!q.empty()) { kk=q.front(); q.pop(); for(int i=0;i<4;i++) { int xx=kk.x+ss[i][0]; int yy=kk.y+ss[i][1]; if(xx<=0||xx>n||yy<=0||yy>m)continue; if(mp[xx][yy]=='X'||mp[xx][yy]=='D')continue; if(kk.t+1<tim[index][xx][yy]){ tim[index][xx][yy]=kk.t+1; hh[xx][yy].x=a; hh[xx][yy].y=b; sss kkk; kkk.x=xx; kkk.y=yy; kkk.t=tim[index][xx][yy]; // cout<<"feinds "<<tim[xx][yy]<<endl;return; q.push(kkk); } } } } using namespace NetFlow; int juge(int r) { init(3000); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++) { if(mp[i][j]=='.') link(1000,(i-1)*m+j,1); } } for(int i=1;i<=cnt;i++)link(n*m+i,1001,r); for(int i=1;i<=cnt;i++) { for(int j=1;j<=n;j++){ for(int k=1;k<=m;k++) { if(tim[n*m+i][j][k]<=r)link((j-1)*m+k,n*m+i,1); } } } // cout<<14<<endl; if(dinic(1000,1001)==tot)return 1; else return 0; } int main() { scanf("%d%d",&n,&m); tot=0; for(int i=1;i<=n;i++) { scanf("%s",mp[i]+1); for(int j=1;j<=m;j++) { if(mp[i][j]=='D') { cnt++; xxx[cnt]=i; yyy[cnt]=j; } if(mp[i][j]=='.')tot++; } } // cout<<"das "<<tot<<endl; memset(tim,127,sizeof(tim)); // if(cnt==0){cout<<"impossible"<<endl;return 0;} for(int i=1;i<=cnt;i++) { bfss(xxx[i],yyy[i],n*m+i); } int l=0; int r=400; int ans=-1; while(l<r) { int mid=(l+r)>>1; if(juge(mid)) { ans=mid; r=mid; } else l=mid+1; } if(ans==-1)cout<<"impossible"<<endl; else cout<<ans<<endl; return 0; }
例子:
4 5
XXDXX
XX.XX
X...X
XXDXX
答案应该输出3
上面的做法是错的,必须要对门的每个时间点都连一条容量为limit-k+1的边才行,
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls | 1 #define mid ((ll+rr)>>1) #define pii pair<int,int> #define MP make_pair typedef long long LL; const long long INF = 1e18+1LL; const double Pi = acos(-1.0); const int N = 5e4+500, M = 1e3+20, mod = 1e9+7, inf = 2e9; int n,m,vis[30][30],step[30][30],all; char mp[30][30]; vector< pair<int,int > > D; vector< pair<int,int > > out[N]; int ss[4][2] = {-1,0,0,-1,1,0,0,1}; int h[N],head[N],t = 2,S,T,q[N],ans; struct edge{int to,next,v;}e[5000010]; void adds(int u,int v,int w) {e[t].next=head[u];e[t].v=w;e[t].to=v;head[u]=t++;} void add(int u,int v,int w) {adds(u,v,w);adds(v,u,0);} int bfs() { memset(h,-1,sizeof(h)); int l = 0,r = 1, now; q[l] = S; h[S] = 0; while(l != r) { now=q[l++];//if(l == 910)l = 0; for(int i=head[now];i!=-1;i=e[i].next) { if(e[i].v&&h[e[i].to] == -1) { h[e[i].to] = h[now] + 1; q[r++] = e[i].to; //if(r == 910) r = 0; } } } if(h[T] == -1) return 0; return 1; } int dfs(int x,int f) { if(x == T) return f; int used=0,w; for(int i=head[x];i!=-1;i=e[i].next) { if(e[i].v&&h[e[i].to] == h[x]+1) { w=dfs(e[i].to,min(f-used,e[i].v)); used+=w;e[i].v-=w;e[i^1].v+=w; if(used == f) return f; } } return used; } int dinic() { while(bfs()) {ans+=dfs(S,inf);} return ans; } int check(int x) { S = n*m+1,T = S + 1; t = 2, memset(head,-1,sizeof(head)); int tot = 1; for(int i = 1; i <= n; ++i) { for(int j = 1; j <= m; ++j) { if(mp[i][j] == '.') { add(S,(i-1)*m+j,1); for(int k = 0; k < out[(i-1)*m+j].size(); ++k) { if(out[(i-1)*m+j][k].first <= x) add((i-1)*m+j,T+(out[(i-1)*m+j][k].second-1)*x+out[(i-1)*m+j][k].first,1); } } if(mp[i][j] == 'D') { add((i-1)*m+j,T,x); for(int k = 1; k <= x; ++k) add(T+(tot-1)*x+k,(i-1)*m+j,x-k+1); tot++; } } } ans = 0; if(dinic() == all) return 1; else return 0; } void bfs(int x,int y,int who) { queue< pair<int ,int > > q; q.push(MP(x,y)); vis[x][y] = 1; step[x][y] = 0; while(!q.empty()) { pair<int,int > k = q.front(); q.pop(); for(int i = 0 ; i < 4; ++i) { int xx = k.first + ss[i][0]; int yy = k.second + ss[i][1]; if(xx <= 0 || yy <= 0 || xx > n || yy > m || mp[xx][yy] != '.') continue; if(vis[xx][yy]) continue; vis[xx][yy] = 1; q.push(MP(xx,yy)); step[xx][yy] = step[k.first][k.second]+1; out[(xx-1)*m+yy].push_back(MP(step[xx][yy],who)); } } } int main() { scanf("%d%d",&n,&m); for(int i = 1; i <= n; ++i) { scanf("%s",mp[i]+1); for(int j = 1; j <= m; ++j) { if(mp[i][j] == 'D') D.push_back(MP(i,j)); if(mp[i][j] == '.') all++; } } for(int i = 0; i < D.size(); ++i) { memset(vis,0,sizeof(vis)); memset(step,0,sizeof(step)); bfs(D[i].first,D[i].second,i+1); } int l = 0, r = 400, ans1 = -1; while(l <= r) { int md = (l+r)>>1; if(check(md)) ans1 = md, r = md - 1; else l = md + 1; } if(ans1 == -1) printf("impossible"); else printf("%d",ans1); return 0; }