2019-CCPC-秦皇島 E Escape (網絡流)

題目鏈接

Escape


題意:

給定一個網格,用 0101 表示, 11 的格子表示障礙,有 aa 個機器人在第 00 行向下,在第 n+1n+1 行有 bb 個出口,機器人只能直走,現在可以在空格上放置轉彎轉置,具體如題目中所示。問是否能夠使得所有機器人走出迷宮。

思路:

由於機器人所在列一定不同,那麼可以發現,對於每一個格子要麼是轉彎,要麼豎直,要麼水平,並且只會經過一次。 如果發現了這個性質題目就好解多了,只要將每一個點拆成兩個點一個表示豎直,一個表示水平,在對每一個點連接水平和豎直就行了,跑一個最大流。
(網絡流的構圖思路還是不行)。

代碼:

#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");
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章