題目鏈接
Escape
題意:
給定一個網格,用 表示, 的格子表示障礙,有 個機器人在第 行向下,在第 行有 個出口,機器人只能直走,現在可以在空格上放置轉彎轉置,具體如題目中所示。問是否能夠使得所有機器人走出迷宮。
思路:
由於機器人所在列一定不同,那麼可以發現,對於每一個格子要麼是轉彎,要麼豎直,要麼水平,並且只會經過一次。 如果發現了這個性質題目就好解多了,只要將每一個點拆成兩個點一個表示豎直,一個表示水平,在對每一個點連接水平和豎直就行了,跑一個最大流。
(網絡流的構圖思路還是不行)。
代碼:
#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");
}
}