P3191 [HNOI2007] 紧急疏散EVACUATE
套路题,给个不用二分的写法。
一眼网络流。
将人看做流量。每个格子拆成两个点,从入点连向出点,如果是门那么容量是
涉及到时间所以建分层图。现在在
对于第一层,源点向每个空地连边,容量为
对于每一层,门位置的出点(入点也行)连向汇点,容量为
但是因为时间不知道,所以不知道要建多少层。所以直接一层一层加上去,然后加上新增的流量,直到第一次总流量等于人数,此时的层数减去一就是答案。
注意判断无解的情况。因为
#include<queue>
#include<cstdio>
#include<cstring>
const int M=5e5+10;
const int inf=1e9+7;
const int dx[]={-1,1,0,0},
dy[]={0,0,-1,1};
int n,m;
char mp[23][23];
int head[M],cnte=1;
struct Edge{
int to,nxt,cap,flow;
}e[M<<2];
void add(int u,int v,int w){
e[++cnte]={v,head[u],w,0};
head[u]=cnte;
}
void Add(int u,int v,int w){
add(u,v,w),add(v,u,0);
}
std::queue<int>q;
int dis[M],s,t,cntp;
bool bfs(){
for(int i=0;i<=cntp;i++) dis[i]=0;
dis[s]=1;
q.push(s);
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head[u];~i;i=e[i].nxt){
int v=e[i].to;
if(e[i].cap>e[i].flow&&!dis[v]){
dis[v]=dis[u]+1;
q.push(v);
}
}
}
return dis[t];
}
int dfs(int u,int in){
if(u==t) return in;
int out=0;
for(int i=head[u];~i;i=e[i].nxt){
int v=e[i].to;
if(dis[v]==dis[u]+1&&e[i].cap>e[i].flow){
int res=dfs(v,std::min(in,e[i].cap-e[i].flow));
e[i].flow+=res,e[i^1].flow-=res;
in-=res,out+=res;
}
}
if(!out) dis[u]=-1;
return out;
}
int Dinic(){
int ans=0;
while(bfs()) ans+=dfs(s,inf);
return ans;
}
int iD[2][23][23][2],cur;
void BasicLayer(){
cur^=1;
s=0,t=cntp=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(mp[i][j]=='X') continue;
iD[1][i][j][0]=++cntp;
iD[1][i][j][1]=++cntp;
if(mp[i][j]=='.'){
Add(iD[1][i][j][0],iD[1][i][j][1],1);
Add(s,iD[1][i][j][0],1);
}
if(mp[i][j]=='D'){
Add(iD[1][i][j][0],iD[1][i][j][1],1);
Add(iD[1][i][j][1],t,1);
}
}
}
void NewLayer(){
cur^=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(mp[i][j]=='X') continue;
iD[cur][i][j][0]=++cntp;
iD[cur][i][j][1]=++cntp;
Add(iD[cur^1][i][j][1],iD[cur][i][j][0],inf);
for(int dir=0;dir<4;dir++){
int x=i+dx[dir],y=j+dy[dir];
if(x<1||x>n||y<1||y>m) continue;
if(mp[x][y]!='.') continue;
Add(iD[cur^1][x][y][1],iD[cur][i][j][0],inf);
}
if(mp[i][j]=='.'){
Add(iD[cur][i][j][0],iD[cur][i][j][1],inf);
}
if(mp[i][j]=='D'){
Add(iD[cur][i][j][0],t,1);
}
}
}
int main(){
memset(head,-1,sizeof head);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf(" %s",mp[i]+1);
int cnt=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) cnt+=(mp[i][j]=='.');
BasicLayer();
int all=0;
for(int t=1;;t++){
if(t>=400) break;
NewLayer();
all+=Dinic();
if(all==cnt){
printf("%d\n",t);
return 0;
}
}
printf("impossible\n");
return 0;
}