【BZOJ3504】【CQOI2014】—危桥(最大流建模)

传送门

不错的一道网络流连手题

一般第一眼都会直接想到的一种似乎正确的做法:

对于危桥连一个流量为 1 1 的边,普通桥连一条 i n f inf 的边
源点向 a l , b l al,bl a n , b n an,bn 的边, a 2 , b 2 a2,b2 向汇点连一条为 a n , b n an,bn 的边
看是不是满流

然而这样是错的…

比如这样

在这里插入图片描述

很明显是错的

那么怎么办?

我们考虑交换其中一对源汇点
然后再跑一次,看是不是仍然是最大流?

为什么是对的呢?

假设我们交换的是 b l , b 2 bl,b2
如果流满了
考虑两种情况:


1. a l al b 2 b2 流满的

由于第一次的时候 a l al b l bl 可以流满
那也就是说 b l bl b 2 b2 也可以流满了
又第一次 b l bl ,第二次 b 2 b2 都和 a 2 a2 能流满
a l al 也总可以流给 a 2 a2
那也就说是可以的


2. a l al a 2 a2 流满的

那不用说了,既然 a l al 可以流满 a 2 a2 ,那肯定就是可以了的


所以如果两次都流满了,那肯定就是可以的
反之肯定不行

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
	return res*f;
}
const int N=71;
const int M=5005;
const int inf=20030224;
int adj[N],nxt[M],to[M],cap[M],tp[N],lev[N],n,cnt,str,des,as,at,an,bs,bt,bn;
char edg[N][N];
inline void addedge(int u,int v,int w){
	nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,cap[cnt]=w;
	nxt[++cnt]=adj[v],adj[v]=cnt,to[cnt]=u,cap[cnt]=0;
}
inline bool bfs(){
	queue<int> q;
	memset(lev,-1,sizeof(lev));
	q.push(str),lev[str]=0;
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int e=adj[u];e;e=nxt[e]){
			int v=to[e];
			if(cap[e]>0&&lev[v]==-1){
				lev[v]=lev[u]+1,q.push(v);
				if(v==des)return true;
			}
		}
	}
	return false;
}
inline int dinic(int u,int flow){
	if(u==des)return flow;
	int res=0;
	for(int &e=tp[u];e;e=nxt[e]){
		int v=to[e];
		if(lev[v]==lev[u]+1&&cap[e]>0){
			int mn=dinic(v,min(flow-res,cap[e]));
			cap[e]-=mn,cap[e^1]+=mn,res+=mn;
			if(flow==res)return res;
		}
	}
	return res;
}
inline int solve(){
	int res=0;
	while(bfs()){
		memcpy(tp,adj,sizeof(adj));
		res+=dinic(str,inf);
	}
	return res;
}
inline void buildedge(){
	memset(adj,0,sizeof(adj)),memset(cap,0,sizeof(cap)),cnt=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			switch(edg[i][j]){
				case 'O':{
					addedge(i,j,1);
					break;
				}
				case 'N':{
					addedge(i,j,inf);
					break;
				}
				case 'X':{
					break;
				}
			}
		}
	}
}
int main(){
	while(scanf("%d",&n)!=EOF){
		as=read()+1,at=read()+1,an=read(),bs=read()+1,bt=read()+1,bn=read();
		str=n+1,des=n+2;
		for(int i=1;i<=n;i++)scanf("%s",edg[i]+1);
		buildedge();
		addedge(str,as,an),addedge(str,bs,bn),addedge(at,des,an),addedge(bt,des,bn);
		int fres=solve();
		buildedge();
		addedge(str,as,an),addedge(str,bt,bn),addedge(at,des,an),addedge(bs,des,bn);
		int res=solve();
		if(res==an+bn&&fres==an+bn)cout<<"Yes"<<'\n';
		else cout<<"No"<<'\n';
	}
}

猜你喜欢

转载自blog.csdn.net/qq_42555009/article/details/86654855
今日推荐