不错的一道网络流连手题
一般第一眼都会直接想到的一种似乎正确的做法:
对于危桥连一个流量为的边,普通桥连一条的边
源点向连的边,向汇点连一条为的边
看是不是满流
然而这样是错的…
比如这样
很明显是错的
那么怎么办?
我们考虑交换其中一对源汇点
然后再跑一次,看是不是仍然是最大流?
为什么是对的呢?
假设我们交换的是
如果流满了
考虑两种情况:
1.到流满的
由于第一次的时候到可以流满
那也就是说到也可以流满了
又第一次,第二次都和能流满
那也总可以流给
那也就说是可以的
2.到流满的
那不用说了,既然可以流满,那肯定就是可以了的
所以如果两次都流满了,那肯定就是可以的
反之肯定不行
#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"<<'
';
else cout<<"No"<<'
';
}
}