P3191 [HNOI2007]紧急疏散EVACUATE
这一题很容易想到网络流
一开始傻逼地模拟整个图每一个时间的情况,显然会爆炸
发现我们只要考虑起点到门之间的距离,不用每一步只走一格
所以直接 $BFS$ 预处理距离然后二分答案,网络流判断即可
注意到了门就不能走了,所以门不能连边出去
总的来说挺傻逼的一题...但是我就是没想到...
某位不愿意透露姓名的神仙还有一种牛逼的费用流做法,代码极短$STO$
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> using namespace std; typedef long long ll; inline int read() { int 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<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=2e5+7,M=5e6+7,INF=1e9+7,xx[4]={0,1,0,-1},yy[4]={1,0,-1,0}; int fir[N],from[M<<1],to[M<<1],val[M<<1],cntt=1; inline void add(int a,int b,int c) { from[++cntt]=fir[a]; fir[a]=cntt; to[cntt]=b; val[cntt]=c; from[++cntt]=fir[b]; fir[b]=cntt; to[cntt]=a; val[cntt]=0; } int n,m,tot,id[507][27][27],sum; int dep[N],S,T; queue <int> Q; bool BFS() { for(int i=0;i<=tot;i++) dep[i]=0; Q.push(S); dep[S]=1; while(!Q.empty()) { int x=Q.front(); Q.pop(); for(int i=fir[x];i;i=from[i]) { int &v=to[i]; if(dep[v]||(!val[i])) continue; dep[v]=dep[x]+1; Q.push(v); } } return dep[T]>0; } int DFS(int x,int mxfl) { if(x==T||!mxfl) return mxfl; int fl=0,res; for(int i=fir[x];i;i=from[i]) { int &v=to[i]; if(dep[v]!=dep[x]+1||!val[i]) continue; if( res=DFS(v,min(mxfl,val[i])) ) { mxfl-=res; fl+=res; val[i]-=res; val[i^1]+=res; if(!mxfl) break; } } return fl; } char mp[233][233]; int dis[27][27][27][27]; struct dat{ int x,y; dat (int a=0,int b=0) { x=a,y=b; } }; queue <dat> q; void pre() { memset(dis,0x3f,sizeof(dis)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(mp[i][j]!='.') continue; q.push(dat(i,j)); dis[i][j][i][j]=0; while(!q.empty()) { dat u=q.front(); q.pop(); for(int k=0;k<4;k++) { int tx=u.x+xx[k],ty=u.y+yy[k]; if(tx<1||tx>n||ty<1||ty>m||mp[tx][ty]=='X'||dis[i][j][tx][ty]<M) continue; dis[i][j][tx][ty]=dis[i][j][u.x][u.y]+1; if(mp[tx][ty]!='D') q.push(dat(tx,ty)); } } } } bool check(int mid) { for(int i=0;i<=tot;i++) fir[i]=0; tot=1; S=0,T=1; cntt=1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(mp[i][j]=='.') id[0][i][j]=++tot,add(S,tot,1); for(int t=1;t<=mid;t++) for(int k=1;k<=n;k++) for(int l=1;l<=m;l++) if(mp[k][l]=='D') id[t][k][l]=++tot,add(tot,T,1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(mp[i][j]!='.') continue; for(int t=1;t<=mid;t++) for(int k=1;k<=n;k++) for(int l=1;l<=m;l++) if(mp[k][l]=='D'&&dis[i][j][k][l]<=t) add(id[0][i][j],id[t][k][l],INF); } int now=0; while(BFS()) { now+=DFS(S,INF); if(now>=sum) break; } for(int t=0;t<=mid;t++) for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) id[t][i][j]=0; return now>=sum; } int main() { n=read(),m=read(); for(int i=1;i<=n;i++) scanf("%s",mp[i]+1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) sum+=(mp[i][j]=='.'); pre(); int L=0,R=n*m,mid,ans=M; while(L<=R) { mid=L+R>>1; if(check(mid)) R=mid-1,ans=mid; else L=mid+1; } if(ans==M) printf("impossible\n"); else printf("%d\n",ans); return 0; }