[洛谷P3851] TJOI2007 脱险

问题背景

一批探险队员正在一个迷宫一样的山洞里摸索,突然他们得到了一个糟糕的消息,由于附近发生地震,这个山洞将有可能在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\n",ans);
	return 0;
}
posted @ 2020-07-13 08:03  CJlzf  阅读(144)  评论(0编辑  收藏  举报