题目描述
Scofild又要策划一次越狱行动,和上次一样,他已经掌握了整个监狱的地图,看守的位置,以及准备好了逃出监狱的出口。由于消息被其他监狱中的囚犯得知了,为了不泄露消息,他不得不将所有人带出监狱。
这是一个月黑风高的夜晚。。。看守们都已经睡着,在没有罪犯打扰的情况下绝对不会醒来,即罪犯不能到达看守所在位置。在每一个空地中,都有一名罪犯,并且同一个空地,能容纳无穷多个罪犯。每个人都只能向东南西北四个方向移动。在地图中某些位置,有一些出口,当罪犯到达出口,就视为逃出监狱,并且出口每一秒钟最多能逃出1个罪犯。现在越狱行动开始。。。Scofild需要安排一个越狱计划,使得大家能尽快的逃出监狱。此时,监狱的监控发现了情况,监狱外的警察,将在T秒后到达现场,并封锁所有出口。现在Scofild想要知道所有人能否成功越狱,如果能,计算出所需的最短的越狱时间,使得最后一个人逃出监狱的时间尽量的短。
输入
第一行三个整数r,c,T(3 <= r, c <= 12)
接下来r行字符,每行c列。‘.’表示一个空地,一开始该点有一名罪犯。‘X’表示警察的位置,并且他不能移动,罪犯也不能到达该点,否则他就会醒来并拉响警报。‘E’表示出口。
输出
1行,输出最少的越狱时间,如果在大批警察赶到之后还有人无法逃离,则输出“impossible”。
样例输入
5 5 3
XXEXX
X…X
E…X
X…E
XXXXX
样例输出
3
每秒钟每个出口只能逃出一个罪犯,这种一一对应的匹配关系,让我们自然而然地想到了二分图最大匹配。我们可以对每个出口与时间,进行裂点操作。先bfs预处理出每个犯罪者到某出口的最短时间,设mintime=x,
则把罪犯与该点的x时间–总时间都连一条边。
那么问题又来了,题目要求我们找出最短的越狱时间,但是普通的最大匹配只是保证匹配完成,并不会管时间怎么样。所以我们可以枚举最短时间,然后匹配的话,如果时间超出当前限制,则不与它匹配,这个枚举时间的过程还可以用二分进一步优化。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
int head[200],Next[3000000],to[3000000],p[15][15],e[15][15];
int xy[20000],mark[20000];
char a[15][15];
int x[200],y[200],z[200],dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
int n,m,Time,tot,es,crime,now,all,limit,l,r;
void add(int x,int y)
{
tot++;
Next[tot]=head[x];
to[tot]=y;
head[x]=tot;
}
void bfs(int X,int Y)
{
crime++;
head[crime]=-1;
int t=0,w=1,len=0;
memset(p,0,sizeof(p));
x[1]=X;y[1]=Y;
p[X][Y]=1;
while(t<w)
{
t++;
if(a[x[t]][y[t]]=='E')
{
for(int i=Time;i>=z[t];i--) add(crime,(e[x[t]][y[t]]-1)*Time+i);
continue;
}
for(int i=0;i<4;i++)
{
int rx=x[t]+dx[i];
int ry=y[t]+dy[i];
if(rx>=1&&rx<=n&&ry>=1&&ry<=m&&p[rx][ry]==0&&a[rx][ry]!='X')
{
w++;
x[w]=rx;
y[w]=ry;
z[w]=z[t]+1;
p[rx][ry]=1;
}
}
}
}
int dfs(int k)
{
for(int i=head[k];i!=-1;i=Next[i])
if(mark[to[i]]!=now)
{
mark[to[i]]=now;
int cost=to[i]%Time;
if(cost==0) cost=Time;
if(cost>limit) continue;
if(xy[to[i]]==-1||dfs(xy[to[i]]))
{
xy[to[i]]=k;
return 1;
}
}
return 0;
}
int match()
{
all=es*Time;
int res=0;
l=1;r=Time;
while(l<=r)
{
limit=(l+r)/2;
for(int j=1;j<=all;j++)
{
xy[j]=-1;
mark[j]=0;
}
now=0,res=0;
for(int j=1;j<=crime;j++)
{
now++;
if(dfs(j)==0) break; else res++;
}
if(res==crime) r=limit-1;else l=limit+1;
}
return l;
}
int main()
{
cin>>n>>m>>Time;
for(int i=1;i<=n;i++) scanf("%s",a[i]+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j]=='E')
{
es++;
e[i][j]=es;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j]=='.') bfs(i,j);
if(match()>Time)
{
cout<<"impossible"<<endl;
return 0;
}
cout<<l;
return 0;
}