问题背景
一批探险队员正在一个迷宫一样的山洞里摸索,突然他们得到了一个糟糕的消息,由于附近发生地震,这个山洞将有可能在T个单位时间后坍塌。现在他们要用最快的速度找出一个方案,使得在T个单位时间内逃出的队员最多。已知探险队员在一个单位时间内可以向前后左右任一方向移动一格,也可以停留在原地不动。有一个糟糕的情况是,虽然山洞的内部比较宽敞,但山洞的出口都非常狭窄,一个单位时间只能允许一名队员通过。
问题描述
山洞的地图用一个R * C的字符矩阵表示,其中'.'表示在开始的时候没有探险队员的空地,空地可以容纳任意多的探险队员;'P'表示在开始的时候有探险队员的空地,我们假设在开始的时候所有的队员都在不同的位置上,且没有队员恰好位于出口所在的方格;' * '表示障碍物,探险队员不能经过被障碍物占据的方格;'O'(大写字母O)表示出口,输入数据保证出口一定位于地图的边界上,即只有第1行,第R行,第1列,第C列有可能出现'O'。另外,输入数据保证整个地图被边界和出口围住,即第1行,第R行,第1列,第C列只能是'*'或'O'.
输入格式
输入文件的第一行是用空格隔开的两个整数R和C,表示地图的大小。第二行是整数T,即山洞将要坍塌的时间。接下来R行,每行包含C个字符,表示一幅山洞地图。
输出格式
输出一行,包含一个整数,即T个单位时间内最多能逃出的人数。
样例输入
5 5
4
*****
*P..*
O**.O
*P..*
*****
样例输出
1
说明
山洞有两个出口,但只有右边的出口是可以到达的。虽然在3个单位时间内两人都可以到达出口左侧的方格处,但由于在出口处一个单位时间只能允许一人通过,故4个单位时间内只能逃出一人。两人都逃出需要5个单位时间。
对于30%的数据,队员数和出口数均不超过10
对于100%的数据,3 ≤ R, C ≤ 12,0 < T ≤ 50
解析
首先BFS出每个人到每一个出口的距离,然后网络流建图,对每一个出口都建T个点,向汇点连容量为1的边,表示在这个时刻只能通过1人。对于每个人,向每一个时间不小于自己到那个出口的距离的点连边,容量为1。Dinic即可。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define N 1000002
#define M N
using namespace std;
const int inf=1<<30;
int head[N],ver[M*2],nxt[M*2],cap[M*2],l;
struct node{
int x,y,d;
node(int _x,int _y,int _d){
x=_x,y=_y,d=_d;
}
};
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
int r,c,t,i,j,k,n,m,n1,n2,S,T,dis[N],flow[N],pre[N],cnt[N],id[102][102],dist[102][102],ans;
char a[50][50];
bool vis[50][50],in[N];
void bfs(int sx,int sy,int p)
{
queue<node> q;
memset(vis,0,sizeof(vis));
q.push(node(sx,sy,0));
vis[sx][sy]=1;
while(!q.empty()){
int x=q.front().x,y=q.front().y,d=q.front().d;
q.pop();
for(int i=0;i<4;i++){
int tx=x+dx[i],ty=y+dy[i];
if(tx>=1&&tx<=r&&ty>=1&&ty<=c&&a[tx][ty]!='*'&&!vis[tx][ty]){
vis[tx][ty]=1;
if(a[tx][ty]=='O') dist[p][id[tx][ty]]=d+1;
q.push(node(tx,ty,d+1));
}
}
}
}
void insert(int x,int y,int z)
{
ver[l]=y;
cap[l]=z;
nxt[l]=head[x];
head[x]=l;
l++;
ver[l]=x;
cap[l]=0;
nxt[l]=head[y];
head[y]=l;
l++;
}
bool bfs()
{
queue<int> q;
memset(dis,-1,sizeof(dis));
q.push(S);
dis[S]=0;
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=head[x];i!=-1;i=nxt[i]){
int y=ver[i];
if(dis[y]==-1&&cap[i]>0){
dis[y]=dis[x]+1;
q.push(y);
}
}
}
return (dis[T]!=-1);
}
int dfs(int x,int flow)
{
if(x==T||flow==0) return flow;
int ans=0;
for(int i=head[x];i!=-1;i=nxt[i]){
int y=ver[i];
if(dis[y]==dis[x]+1&&cap[i]>0){
int a=dfs(y,min(flow,cap[i]));
flow-=a;ans+=a;
cap[i]-=a;cap[i^1]+=a;
}
if(flow==0) break;
}
if(flow) dis[x]=-1;
return ans;
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d%d",&r,&c,&t);
for(i=1;i<=r;i++) scanf("%s",a[i]+1);
for(i=1;i<=r;i++){
for(j=1;j<=c;j++){
if(a[i][j]=='P') id[i][j]=++n1;
}
}
for(i=1;i<=r;i++){
for(j=1;j<=c;j++){
if(a[i][j]=='O') id[i][j]=(++n2)+n1;
}
}
for(i=1;i<=r;i++){
for(j=1;j<=c;j++){
if(a[i][j]=='P') bfs(i,j,id[i][j]);
}
}
n=n1+n2*t+1,T=n;
for(i=1;i<=n1;i++) insert(S,i,1);
for(i=n1+1;i<=n1+n2*t;i++) insert(i,T,1);
for(i=1;i<=t;i++){
for(j=1;j<=n1;j++){
for(k=n1+1;k<=n1+n2;k++){
if(dist[j][k]<=i&&dist[j][k]!=0){
insert(j,n1+(k-n1-1)*t+i,1);
}
}
}
}
while(bfs()) ans+=dfs(S,inf);
printf("%d
",ans);
return 0;
}