题目链接
Escape
题意:
给定一个网格,用 01 01 01 表示, 1 1 1 的格子表示障碍,有 a a a 个机器人在第 0 0 0 行向下,在第 n + 1 n+1 n+1 行有 b b b 个出口,机器人只能直走,现在可以在空格上放置转弯转置,具体如题目中所示。问是否能够使得所有机器人走出迷宫。
思路:
由于机器人所在列一定不同,那么可以发现,对于每一个格子要么是转弯,要么竖直,要么水平,并且只会经过一次。 如果发现了这个性质题目就好解多了,只要将每一个点拆成两个点一个表示竖直,一个表示水平,在对每一个点连接水平和竖直就行了,跑一个最大流。
(网络流的构图思路还是不行)。
代码:
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#define inf 1e18
#define ll long long
using namespace std;
const int N=1e5+10;
const int M=1e6+10;
struct Maxflow{
int h[N],cur[N],ne[M],to[M],tot,deep[N],s,t,mx;
ll flow[M],ans;
inline void init(int a,int b,int c){
s=a;t=b;mx=c;
for(int i=0;i<M;i++)ne[i]=0;
for(int i=0;i<N;i++)h[i]=0;
tot=1;ans=0;
}
inline void addedge(int x,int y,int z){
to[++tot]=y;ne[tot]=h[x],h[x]=tot,flow[tot]=z;
swap(x,y);
to[++tot]=y;ne[tot]=h[x],h[x]=tot,flow[tot]=0;
}
inline bool bfs(){
for(int i=0;i<=mx;i++)deep[i]=-1;
queue<int>q;
q.push(s);deep[s]=0;
for(int i=0;i<=mx;i++)cur[i]=h[i];
while(!q.empty())
{
int now=q.front();q.pop();
for(int i=h[now];i;i=ne[i]){
int v=to[i];
if(deep[v]==-1&&flow[i]>0)deep[v]=deep[now]+1,q.push(v);
}
}
return deep[t]!=-1;
}
inline ll dfs(int u,ll op){
if(u==t||op==0)return op;
ll f=0,us=0;
for(int i=cur[u];i;i=ne[i]){
cur[u]=i;
int v=to[i];
if(deep[v]==deep[u]+1&&flow[i]>0){
us=dfs(v,min(op,flow[i]));
if(!us)continue;
f+=us;op-=us;
flow[i]-=us;flow[i^1]+=us;
if(!op)break;
}
}
if(!f)deep[u]=-1;
return f;
}
inline ll maxflow(){
while(bfs()){
ans+=dfs(s,inf);
}
return ans;
}
}F;
int T,n,m,a,b;
int get(int x,int y){
return (x-1)*m+y;
}
char tu[200][200];
int main()
{
scanf("%d",&T);
while(T--){
scanf("%d%d%d%d",&n,&m,&a,&b);
int s=2*n*m+1,t=2*n*m+2;
F.init(s,t,t);
for(int i=1;i<=n;i++){
scanf("%s",tu[i]+1);
}
for(int i=1,x;i<=a;i++){
scanf("%d",&x);
F.addedge(s,get(1,x),1);
}
for(int i=1,x;i<=b;i++){
scanf("%d",&x);
F.addedge(get(n,x),t,1e9);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(tu[i][j]!='1'){//注意是字符的1
if(i+1<=n)F.addedge(get(i,j),get(i+1,j),1);
if(i-1>=1)F.addedge(get(i,j),get(i-1,j),1);//竖直
if(j+1<=m)F.addedge(get(i,j)+n*m,get(i,j+1)+n*m,1);
if(j-1>=1)F.addedge(get(i,j)+n*m,get(i,j-1)+n*m,1);//水平
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(tu[i][j]!='1')F.addedge(get(i,j),get(i,j)+n*m,1),F.addedge(get(i,j)+n*m,get(i,j),1);//转弯
}
int ans=F.maxflow();
if(ans==a){
puts("Yes");
}else puts("No");
}
}