Description
发生了火警,所有人员需要紧急疏散!假设每个房间是一个N
M的矩形区域。每个格子如果是’.’,那么表示这是一块空地;如果是’X’,那么表示这是一面墙,如果是’D’,那么表示这是一扇门,人们可以从这儿撤出房间。已知门一定在房间的边界上,并且边界上不会有空地。最初,每块空地上都有一个人,在疏散的时候,每一秒钟每个人都可以向上下左右四个方向移动一格,当然他也可以站着不动。疏散开始后,每块空地上就没有人数限制了(也就是说每块空地可以同时站无数个人)。但是,由于门很窄,每一秒钟只能有一个人移动到门的位置,一旦移动到门的位置,就表示他已经安全撤离了。现在的问题是:如果希望所有的人安全撤离,最短需要多少时间?或者告知根本不可能。
Input输入文件第一行是由空格隔开的一对正整数N与M,3<=N <=20,3<=M<=20,以下N行M列描述一个N
M的矩阵。其中的元素可为字符’.’、’X’和’D’,且字符间无空格。 Output只有一个整数K,表示让所有人安全撤离的最短时间,如果不可能撤离,那么输出’impossible’(不包括引号)。
先预处理出每个空地到每个门的时间,然后把门按照时间拆点,二分答案,把同一时间只能有一个人到达门等价地看成每个时刻门只能出去一个人,剩下的人要在原地等待。从原点向空地连容量为1的边,从空地向到达时间的门连容量为1的边,满足时间要求的门向汇点连容量为1的边,每个时刻的门向下一时刻的自己连容量无穷大的边。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int s=50005,t=50006,oo=0x3f3f3f3f;
int fir[50010],ne[2000010],to[2000010],w[2000010],xx[]={1,-1,0,0},yy[]={0,0,1,-1},
dis[410][410],num[25][25],qx[410],qy[410],f[50010],que[50010],
n,m,tot,clo,fcnt,dcnt;
char map[25][25];
bool is(int x,int y)
{
return x>=1&&x<=n&&y>=1&&y<=m&&map[x][y]=='.';
}
void init()
{
int i,j,hd,tl,x,y,x1,y1,k;
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++)
{
scanf("%s",map[i]+1);
for (j=1;j<=m;j++)
{
if (map[i][j]=='.')
num[i][j]=++fcnt;
if (map[i][j]=='D')
num[i][j]=++dcnt;
}
}
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
if (map[i][j]=='D')
{
for (k=1;k<=fcnt;k++)
dis[num[i][j]][k]=oo;
hd=1;
tl=0;
for (k=0;k<4;k++)
if (is(x1=i+xx[k],y1=j+yy[k]))
{
dis[num[i][j]][num[x1][y1]]=1;
qx[++tl]=x1;
qy[tl]=y1;
}
while (hd<=tl)
{
x=qx[hd];
y=qy[hd++];
for (k=0;k<4;k++)
if (is(x1=x+xx[k],y1=y+yy[k])&&dis[num[i][j]][num[x1][y1]]==oo)
{
dis[num[i][j]][num[x1][y1]]=dis[num[i][j]][num[x][y]]+1;
qx[++tl]=x1;
qy[tl]=y1;
}
}
}
}
bool judge()
{
int i,j,flag;
for (i=1;i<=fcnt;i++)
{
flag=0;
for (j=1;j<=dcnt;j++)
if (dis[j][i]<oo)
{
flag=1;
break;
}
if (!flag) return 1;
}
return 0;
}
void add(int u,int v,int x)
{
tot++;
ne[tot*2]=fir[u];
fir[u]=tot*2;
to[tot*2]=v;
w[tot*2]=x;
ne[tot*2+1]=fir[v];
fir[v]=tot*2+1;
to[tot*2+1]=u;
w[tot*2+1]=0;
}
bool bfs()
{
int i,hd,tl,u,v;
memset(f,0,sizeof(f));
f[s]=1;
hd=tl=1;
que[1]=s;
while (hd<=tl)
{
u=que[hd++];
for (i=fir[u];i;i=ne[i])
if (w[i]&&!f[v=to[i]])
{
f[v]=f[u]+1;
que[++tl]=v;
}
}
return f[t];
}
int dfs(int u,int lim)
{
int ret=0,x,i,v;
if (u==t) return lim;
for (i=fir[u];i&&ret<lim;i=ne[i])
if (w[i]&&f[v=to[i]]==f[u]+1)
{
x=dfs(v,min(lim-ret,w[i]));
ret+=x;
w[i]-=x;
w[i^1]+=x;
}
if (!ret) f[u]=0;
return ret;
}
bool ok(int x)
{
int i,j;
tot=0;
memset(fir,0,sizeof(fir));
for (i=1;i<=fcnt;i++)
add(s,i,1);
for (i=1;i<=fcnt;i++)
for (j=1;j<=dcnt;j++)
if (dis[j][i]<=x)
add(i,dcnt*dis[j][i]+j+fcnt,1);
for (i=1;i<=dcnt;i++)
for (j=1;j<=x;j++)
{
add(dcnt*j+i+fcnt,t,1);
if (j>1) add(dcnt*(j-1)+i+fcnt,dcnt*j+i+fcnt,oo);
}/*
if (x==3){
for (i=1;i<=50006;i++)
for (j=fir[i];j;j=ne[j])
if (w[j]) printf("%d->%d:%d\n",i,to[j],w[j]);}*/
while (bfs()) while (dfs(s,oo));
for (i=fir[s];i;i=ne[i])
if (w[i]) return 0;
return 1;
}
int main()
{
int l,r,mid;
init();
if (judge())
{
printf("impossible\n");
return 0;
}
l=0;
r=m*n;
while (l<r)
{
mid=(l+r)/2;
if (ok(mid)) r=mid;
else l=mid+1;
}
printf("%d\n",l);
}