您的位置:首页 > 理论基础 > 计算机网络

bzoj3504 [Cqoi2014]危桥 (网络流 最大流)

2017-12-06 21:12 357 查看

bzoj3504: [Cqoi2014]危桥

原题地址http://www.lydsy.com/JudgeOnline/problem.php?id=3504

题意:

Alice和Bob居住在一个由N座岛屿组成的国家,岛屿被编号为0到N-1。某些岛屿之间有桥相连,桥上的道路是双向的,但一次只能供一人通行。其中一些桥成为危桥,最多只能通行两次。Alice希望在岛屿al和a2之间往返an次(从al到a2再从a2到al算一次往返)。同时,Bob希望在岛屿bl和b2之间往返bn次。这个过程中,所有危桥最多通行两次,其余的桥可以无限次通行。请问Alice和Bob能完成他们的愿望吗?

数据范围

4<=N<50

O<=a1, a2, b1, b2<=N-1

1 <=an. b<=50

题解:

很容易想到网络流,最容易想的建边方式是:

危桥:双向各一条容量为1的边(当然还各有反边,共四条边)

普通桥:双向各一条容量为inf的边

S到a1给an的流量,S到b1给bn的流量,a2->T,b2->T,看是否满流。

但是这样有两个问题:



1、b1与a2相通,那么b1的流入就可以不通过b2到达T,而是通过走a2到达T。

2、同一个危桥,a1->a2与b1->b2走这座桥是不同方向的,而正反流量都是1,那么两次往返都可能会走到这座桥,就是4次,但不会被判出来。

而解决这些问题的办法:

交换b1,b2再跑一次。

即,把S连向b2,b1连向T再跑一次。要两次都合法才算合法。

方向变了解决了问题二,而对于问题一:

如果 b2仍然可以”绕路”,那么b1,b2都可绕到a2的路相连就成了一条路,

因此两次都合法就合法了

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#define LL long long
using namespace std;
queue<int> Q;
const int N=55;
const int inf=10000;
int S,T,n,head
,to[4*N*N],nxt[4*N*N],w[4*N*N],a1,a2,an,b1,b2,bn,num,dep
;
bool vis
;
char s

;
void build(int u,int v,int ww)
{
num++;
to[num]=v;
nxt[num]=head[u];
w[num]=ww;
head[u]=num;
num++;
to[num]=u;
nxt[num]=head[v];
w[num]=0;
head[v]=num;
}
void init(int opt)
{
memset(head,0,sizeof(head)); num=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(s[i][j]=='O') build(i,j,1);
else if(s[i][j]=='N') build(i,j,inf);
}
}
build(S,a1,an);build(a2,T,inf);
if(opt==1) {build(S,b1,bn); build(b2,T,inf);}
else {build(S,b2,bn); build(b1,T,inf);}
}
bool bfs()
{
while(!Q.empty()) Q.pop();
memset(vis,0,sizeof(vis));
memset(dep,0,sizeof(dep));
vis[S]=1; dep[S]=1; Q.push(S);
while(!Q.empty())
{
int u=Q.front(); Q.pop();
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(vis[v]||w[i]<=0) continue;
dep[v]=dep[u]+1; vis[v]=1;
Q.push(v);
}
}
return vis[T];
}
int dfs(int u,int d)
{
if(!d||u==T) return d;
int ret=0;
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(dep[v]!=dep[u]+1||w[i]<=0) continue;
int flow=dfs(v,min(d,w[i]));
ret+=flow;
d-=flow;
w[i]-=flow;
w[i^1]+=flow;
}
if(ret==0) dep[u]=-1;
return ret;
}
bool check()
{
int ret=0;
while(bfs())
{
ret+=dfs(S,inf);
}
return ret>=an+bn;
}
int main()
{
while(scanf("%d%d%d%d%d%d%d",&n,&a1,&a2,&an,&b1,&b2,&bn)!=EOF)
{
a1++; a2++; b1++;b2++; S=n+1; T=n+2;
for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
bool flag=1;
for(int opt=1;opt<=2;opt++)
{
init(opt);
if(!check()) flag=0;
}
if(!flag) printf("No\n");
else printf("Yes\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: