2019CCPC 秦皇岛 E.Escape
题目:http://acm.hdu.edu.cn/showproblem.php?pid=6735
分析:
对于每一个点,接纳的方向永远只有一个
如果两个点到达同一个点,唯一的可能性是他们从起始点到该点的路径完全一致,但是根据题意,起始点是各不相同的,所以任何一个点都不会被重复经过。
每一个点被经过的可能性只可能是以下两种
- 没有转弯装置:水平经过或者竖直经过
- 有转弯装置:从水平到竖直或从竖直到水平
建图:
将每一个点拆分成两个方向:竖直方向
c
o
l
[
i
]
[
j
]
col[i][j]
col[i][j]和水平方向
r
o
w
[
i
]
[
j
]
row[i][j]
row[i][j]的节点,并连一条边,容量为1,表示最多一次的方向转换
竖直与竖直相连
水平与水平相连
起点连到每一个 p i p_i pi的竖直方向,容量为1,表示一个机器人出发
每一个 e i e_i ei的竖直方向连向终点,容量为INF,表示该逃脱点有无限个机器人可以出去(实际上,根据之前的分析,每一个逃脱点最多只有一个机器人可以逃出,所以容量也可以设置为1)
最后跑一遍最大流,如果 m a x f l o w = = a maxflow==a maxflow==a就说明全部可以逃出来
代码:
const int maxn=2e5+7;
const int INF=0x3f3f3f3f;
const ll INFF=1e18;
struct node
{
int to,next,cap,flow;
}edge[maxn];
int tol,m,n,a,b,c,t,mapp[200][200],row[200][200],col[200][200],p,e;
int head[maxn],Q[maxn],dep[maxn],pre[maxn],cur[maxn],sta[maxn];
void init()
{
tol=0;
mem(head,-1);
}
void add(int u,int v,int w)
{
edge[tol].to=v;edge[tol].cap=w;edge[tol].next=head[u];
edge[tol].flow=0;head[u]=tol++;
edge[tol].to=u;edge[tol].cap=0;edge[tol].next=head[v];
edge[tol].flow=0;head[v]=tol++;
}
bool bfs(int sx,int ex,int n)
{
int front=0,tail=0;
mem(dep,-1);
dep[sx]=0;
Q[tail++]=sx;
while(front<tail)
{
int u=Q[front++];
for (int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if (edge[i].cap>edge[i].flow&&dep[v]==-1)
{
dep[v]=dep[u]+1;
if (v==ex)return true;
Q[tail++]=v;
}
}
}
return false;
}
int dinic(int sx,int ex,int n)
{
int maxflow=0;
while(bfs(sx,ex,n))
{
rep(i,0,n)cur[i]=head[i];
int u=sx,tail=0;
while(cur[sx]!=-1)
{
if (u==ex)
{
int tp=INF;
for (int i=tail-1;i>=0;i--)tp=min(tp,edge[sta[i]].cap-edge[sta[i]].flow);
maxflow+=tp;
for (int i=tail-1;i>=0;i--)
{
edge[sta[i]].flow+=tp;
edge[sta[i]^1].flow-=tp;
if (edge[sta[i]].cap-edge[sta[i]].flow==0)tail=i;
u=edge[sta[tail]^1].to;
}
}
else if (cur[u]!=-1&&edge[cur[u]].cap>edge[cur[u]].flow&&dep[u]+1==dep[edge[cur[u]].to])
{
sta[tail++]=cur[u];
u=edge[cur[u]].to;
}
else
{
while(u!=sx&&cur[u]==-1)u=edge[sta[--tail]^1].to;
cur[u]=edge[cur[u]].next;
}
}
}
return maxflow;
}
int main()
{
scanf("%d",&t);
while(t--)
{
init();
scanf("%d%d%d%d",&n,&m,&a,&b);
rep(i,1,n)rep(j,1,m)scanf("%1d",&mapp[i][j]);
int st=0,ed=1,cnt=1;
rep(i,1,n)rep(j,1,m)row[i][j]=++cnt;
rep(i,1,n)rep(j,1,m)col[i][j]=++cnt;
rep(i,1,a)
{
scanf("%d",&p);
add(st,col[1][p],1);
}
rep(i,1,b)
{
scanf("%d",&e);
add(col[n][e],ed,1);
}
rep(i,1,n)
{
rep(j,1,m)
{
if (mapp[i][j])continue;
if (j!=m&&!mapp[i][j+1])
{
add(row[i][j],row[i][j+1],1);
add(row[i][j+1],row[i][j],1);
}
if (i!=n&&!mapp[i+1][j])
{
add(col[i][j],col[i+1][j],1);
add(col[i+1][j],col[i][j],1);
}
add(row[i][j],col[i][j],1);
add(col[i][j],row[i][j],1);
}
}
if (dinic(st,ed,cnt)==a)printf("Yes\n");
else printf("No\n");
}
return 0;
}