bzoj千题计划132:bzoj1189: [HNOI2007]紧急疏散evacuate

时间:2022-04-25 07:08:31

http://www.lydsy.com/JudgeOnline/problem.php?id=1189

二分答案

源点向人连边,流量为1

门拆为mid个点,同一个门的第j个点向第j+1个点连边,流量为inf

若第i个人第k秒到达第j个门,第i个人向第j个门拆出的第k个点连边,流量为1

所有门向汇点连边,流量为1

用ISAP写的,真快,也真TM长

#include<queue>
#include<cstdio>
#include<algorithm>
#include<cstring> using namespace std; #define N 36001
#define M 320001 const int inf=; int mp[][]; int n,m,cnt;
char s[]; int sum[],tim[N][],wh[N][]; int sum_door,doorx[],doory[],id_door[][]; int dis[][];
int dx[]={-,,,};
int dy[]={,,,-}; int tot;
int front[N],nxt[M<<],to[M<<],val[M<<],from[M<<];
int lev[N],num[N];
int path[N];
int cur[N]; int src,decc; struct node
{
int x,y;
}nw,nt; bool inmap(int x,int y)
{
if(x<= || x>n || y<= || y>m) return false;
return mp[x][y];
} void prebfs(int x,int y)
{
queue<node>q;
nw.x=x; nw.y=y;
q.push(nw);
while(!q.empty())
{
nw=q.front();
q.pop();
for(int i=;i<;++i)
{
nt.x=nw.x+dx[i];
nt.y=nw.y+dy[i];
if(!inmap(nt.x,nt.y)) continue;
if(!dis[nt.x][nt.y])
{
dis[nt.x][nt.y]=dis[nw.x][nw.y]+;
if(mp[nt.x][nt.y]==) continue;
q.push(nt);
}
}
}
} void add(int u,int v,int w)
{
to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; from[tot]=u; val[tot]=w;
to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; from[tot]=v; val[tot]=;
} void rebuild(int mid)
{
tot=;
memset(front,,sizeof(front));
decc=mid*sum_door+cnt+;
for(int i=;i<=cnt;++i) add(src,i,);
for(int i=;i<=sum_door;++i)
for(int j=;j<=mid;++j)
{
add((i-)*mid+j+cnt,decc,);
if(j!=mid) add((i-)*mid+j+cnt,(i-)*mid+j+cnt+,inf);
}
for(int i=;i<=cnt;++i)
for(int j=;j<=sum[i];++j)
if(tim[i][j]<=mid) add(i,(wh[i][j]-)*mid+tim[i][j]+cnt,);
} bool bfs()
{
queue<int>q;
for(int i=src;i<=decc;++i) lev[i]=decc;
q.push(decc);
lev[decc]=;
int now,t;
while(!q.empty())
{
now=q.front();
q.pop();
for(int i=front[now];i;i=nxt[i])
{
t=to[i];
if(lev[t]==decc && val[i^])
{
lev[t]=lev[now]+;
q.push(t);
}
}
}
return lev[src]!=decc;
} int augment()
{
int now=decc,flow=inf;
int i;
while(now!=src)
{
i=path[now];
flow=min(flow,val[i]);
now=from[i];
}
now=decc;
while(now!=src)
{
i=path[now];
val[i]-=flow;
val[i^]+=flow;
now=from[i];
}
return flow;
} int isap()
{
int flow=;
if(!bfs()) return ;
memset(num,,sizeof(num));
for(int i=src;i<=decc;++i) num[lev[i]]++,cur[i]=front[i];
int now=src,t;
while(lev[src]<=decc)
{
if(now==decc)
{
flow+=augment();
now=src;
}
bool advanced=false;
for(int i=cur[now];i;i=nxt[i])
{
t=to[i];
if(lev[t]==lev[now]- && val[i])
{
advanced=true;
path[t]=i;
cur[now]=i;
now=t;
break;
}
}
if(!advanced)
{
int mi=decc;
for(int i=front[now];i;i=nxt[i])
if(val[i]) mi=min(mi,lev[to[i]]);
if(!--num[lev[now]]) break;
num[lev[now]=mi+]++;
cur[now]=front[now];
if(now!=src) now=from[path[now]];
}
}
return flow;
} bool check(int mid)
{
rebuild(mid);
return isap()==cnt;
} int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;++i)
{
scanf("%s",s+);
for(int j=;j<=m;++j)
{
if(s[j]=='.') mp[i][j]=;
else if(s[j]=='D')
{
sum_door++;
doorx[sum_door]=i;
doory[sum_door]=j;
mp[i][j]=;
id_door[i][j]=sum_door;
}
}
}
for(int i=;i<=n;++i)
for(int j=;j<=m;++j)
{
if(mp[i][j]!=) continue;
cnt++;
memset(dis,,sizeof(dis));
prebfs(i,j);
for(int i=;i<=sum_door;++i)
{
if(dis[doorx[i]][doory[i]])
{
tim[cnt][++sum[cnt]]=dis[doorx[i]][doory[i]];
wh[cnt][sum[cnt]]=id_door[doorx[i]][doory[i]];
}
}
}
int l=,r=,mid,ans=-;
while(l<=r)
{
mid=l+r>>;
if(check(mid)) ans=mid,r=mid-;
else l=mid+;
}
if(ans==-) printf("impossible");
else printf("%d",ans);
return ;
}

1189: [HNOI2007]紧急疏散evacuate

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 3362  Solved: 994
[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

Sample Output

3