CCPC2019秦皇岛 - Escape

Escape

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 0 Accepted Submission(s): 0

Problem Description
给一个 n×m 大小的迷宫,左上角为 (1,1),右下角为 (n,m)。迷宫中的每个 1×1 的格子要么是障碍,要么为空。

有 a 个机器人要从迷宫上方走到迷宫下方,其中第 i 个机器人的初始位置为 (1,pi) 的正上方,不妨记为 (0,pi),初始运动方向为向下,即 (1,0)。

迷宫有 b 个出口,其中第 i 个出口位于 (n,ei) 的正下方,不妨记为 (n+1,ei)。

现在你想要让这些机器人走出迷宫,但是这些机器人只会沿着当前的运动方向走,不会转弯,所以你需要在迷宫中的某些空格子上设置转弯装置,每个格子上最多只能有一个转弯装置,转弯装置有 NW'',NE’’,SW'',SE’’ 4 种,其中:

"NW’’ 装置会把从格子上方走来的机器人的运动方向变成向左,以及把从格子左方走来的机器人的运动方向变成向上,不允许机器人从格子的右方及下方进入。

"NE’’ 装置会把从格子上方走来的机器人的运动方向变成向右,以及把从格子右方走来的机器人的运动方向变成向上,不允许机器人从格子的左方及下方进入。

"SW’’ 装置会把从格子下方走来的机器人的运动方向变成向左,以及把从格子左方走来的机器人的运动方向变成向下,不允许机器人从格子的右方及上方进入。

"SE’’ 装置会把从格子下方走来的机器人的运动方向变成向右,以及把从格子右方走来的机器人的运动方向变成向下,不允许机器人从格子的左方及上方进入。

你想知道,是否存在一种设置转弯装置的方案,使得所有机器人都能在不经过障碍格子以及不非法进入转弯装置的情况下走出迷宫(允许多个机器人经过同一个格子)。能则输出 Yes'',不能则输出No’’。

Input
输入第一行一个正整数 T,表示数据组数。

对于每组数据:

第一行四个正整数 n,m,a,b,表示迷宫的大小,机器人个数,出口个数。

接下来 n 行,每行一个长为 m 的 01 字符串 si,表示迷宫,其中第 i 个字符串的第 j 个字符表示迷宫中 (i,j) 的状态 —— 0 表示为空,1 表示为障碍。

接下来一行 a 个互不相同的正整数 pi,表示机器人的初始位置 (0,pi)。

接下来一行 b 个互不相同的正整数 ei,表示出口的位置 (n+1,ei)。

1≤T≤10

1≤n,m≤100,1≤a,b,pi,ei≤m

Output
输出共 T 行,每行一个字符串 Yes'' 或者No’’,表示对应数据的答案。

Sample Input
2
3 4 2 2
0000
0011
0000
1 4
2 4
3 4 2 2
0000
0011
0000
3 4
2 4

Sample Output
Yes
No


明显的最大流,主要是怎么去建图。

我们对于每个位置都可以放一个转弯装置,我们可以试想:有没有可能在安装了装置的地方,经过两个机器人?答案是否定的。因为最开始机器人都是向下走的,而且同一个位置只有一个机器人,那么要到达同一个转弯装置,那么肯定经过了转弯,但是转弯装置只能有两个方向通行,所以是否定的。

所以每个机器人要么一直向下走,要么可以转弯。即把点拆成上下走的点和左右走的点,流量为1,上下走的点和左右走的点之间流量为1,代表可以转弯一次,具体怎么转弯都是可以的。

然后判断最大流即可。


AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int inf=0x3f3f3f3f;
const int N=40010,M=1000010;
int T,n,m,a,b,h[N],s,t,base;
char g[110][110];
int head[N],nex[M],w[M],to[M],tot;
inline void ade(int a,int b,int c){
	to[++tot]=b; nex[tot]=head[a]; w[tot]=c; head[a]=tot;
}
inline void add(int a,int b,int c){
	ade(a,b,c);	ade(b,a,0);
}
inline int id(int x,int y){
	return m*x+y;
}
inline int bfs(){
	memset(h,0,sizeof h);	h[s]=1;	queue<int> q;	q.push(s);
	while(q.size()){
		int u=q.front();	q.pop();
		for(int i=head[u];i;i=nex[i]){
			if(!h[to[i]]&&w[i]){
				h[to[i]]=h[u]+1;	q.push(to[i]);
			}
		}
	}
	return h[t];
}
int dfs(int x,int f){
	if(x==t)	return f;	int fl=0;
	for(int i=head[x];i&&f;i=nex[i]){
		if(h[to[i]]==h[x]+1&&w[i]){
			int mi=dfs(to[i],min(w[i],f));
			w[i]-=mi; w[i^1]+=mi; fl+=mi; f-=mi;
		}
	}
	if(!fl)	h[x]=-1;
	return fl;
}
int dinic(){
	int res=0;
	while(bfs())	res+=dfs(s,inf);
	return res;	
}
signed main(){
	cin>>T;
	while(T--){
		tot=1;	memset(head,0,sizeof head);
		cin>>n>>m>>a>>b;	base=(n+2)*m;	t=base*2;
		for(int i=1;i<=n;i++)	scanf("%s",g[i]+1);
		for(int i=1;i<=a;i++){
			int x;	scanf("%d",&x);	g[0][x]='1';
			add(s,id(0,x),1);	add(id(0,x),id(1,x),1);
		}
		for(int i=1;i<=b;i++){
			int x;	scanf("%d",&x);	g[n+1][x]='1';
			add(id(n+1,x),t,inf);	add(id(n,x),id(n+1,x),inf);
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				if(g[i][j]=='1')	continue;
				if(i-1>=1)	add(id(i,j),id(i-1,j),1);
				if(i+1<=n)	add(id(i,j),id(i+1,j),1);
				if(j-1>=1)	add(id(i,j)+base,id(i,j-1)+base,1);
				if(j+1<=m)	add(id(i,j)+base,id(i,j+1)+base,1);
				add(id(i,j),id(i,j)+base,1);	add(id(i,j)+base,id(i,j),1);
			}
		}
		puts(dinic()==a?"Yes":"No");
	}
	return 0;
}
全部评论

相关推荐

点赞 评论 收藏
分享
10-30 23:23
已编辑
中山大学 Web前端
去B座二楼砸水泥地:这无论是个人素质还是专业素质都👇拉满了吧
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务