CQOI 2014 危桥(网络流)

【CQOI2014】危桥

问题描述

Alice和Bob居住在一个由N个岛屿组成的国家,岛屿被编号为0到N-1。某些岛屿之间有桥相连,桥上的道路都是双向的,但是一次只能供一人通行。其中一些桥由于年久失修成为危桥,最多只能通行两次。

Alice希望在岛屿a1和a2之间往返an次(从a1到a2再从a2到a1算一次往返)。同时,Bob希望在岛屿b1和b2之间往返bn次。这个过程中,所有危桥最多通行两次,其余桥可以无限次通行。请问Alice和Bob能完成他们的愿望吗?

输入格式

本题有多组测试数据。

每组数据第一行包含7个空格隔开的整数,分别是N,a1,a2,an,b1,b2,bn。

接下来是一个N行N列的对称矩阵,由大写字母组成。矩阵的第i行第j列描述编号i-1和j-1的岛屿间连接情况,若为“O”则表示有危桥相连;为“N”表示有普通桥相连;为“X”表示没有桥相连。

输出格式

对每组测试数据输出一行,如果他们都能完成愿望输出“Yes”,否则输出“No”。

样例输入

4 0 1 1 2 3 1

XOXX

OXOX

XOXO

XXOX

4 0 2 1 1 3 2

XNXO

NXOX

XOXO

OXOX

样例输出

Yes

No

提示

4<=N<=50

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

1<=an,bn<=50


考虑直接将源点连到a1,b1,将a2,b2连到汇点,然后按题意连边之后直接跑最大流,如果最大流是$an+bn$那么可行。

但是这样做的问题在于可能存在$a1\rightarrow b2$,$b1\rightarrow a2$的流。

处理方法是再跑一次,将a1,a2交换后再做一次最大流,如果最大流也是$an+bn$那么就可行。

证明的话,考虑第二次跑的时候是不存在$a1\rightarrow b2$,$b1\rightarrow a2$的流的,这说明不要这两种流也是可以满足条件的,结合第一次跑的结果,即可保证一定可行。


代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#define N 100000
using namespace std;
int n,a1,a2,an,b1,b2,bn,S,T,ans1,ans2,tot,id[55][55];
int TOT,LA[N],NE[N],EN[N],G[N];
int dis[N],cnt[N];
char map[55][55];
void ADD(int x,int y,int z)
{
TOT++;
EN[TOT]=y;
G[TOT]=z;
NE[TOT]=LA[x];
LA[x]=TOT;
}
int SAP(int x,int f)
{
if(x==T)return f;
int i,y,d=0,tmp;
for(i=LA[x];i;i=NE[i])
{
y=EN[i];
if(!G[i]||dis[x]!=dis[y]+1)continue;
tmp=SAP(y,min(G[i],f-d));
d+=tmp;G[i]-=tmp;G[i^1]+=tmp;
if(d==f||dis[S]>T)return d;
}
if(!--cnt[dis[x]])dis[S]=T+1;
cnt[++dis[x]]++;
return d;
}
void Build(int x1,int x2,int y1,int y2)
{
memset(LA,0,sizeof(LA));TOT=0;
int i,j;
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
{
if(map[i][j]=='O')
{
ADD(n+id[i][j],n+tot+id[i][j],2);
ADD(n+tot+id[i][j],n+id[i][j],0);
}
if(map[i][j]=='N')
{
ADD(n+id[i][j],n+tot+id[i][j],1e9);
ADD(n+tot+id[i][j],n+id[i][j],0);
}
ADD(i,n+id[i][j],1e9);ADD(n+id[i][j],i,0);
ADD(j,n+id[i][j],1e9);ADD(n+id[i][j],j,0);
ADD(n+tot+id[i][j],i,1e9);ADD(i,n+tot+id[i][j],0);
ADD(n+tot+id[i][j],j,1e9);ADD(j,n+tot+id[i][j],0);
}
x1++;x2++;y1++;y2++;
S=n+tot+tot+1;T=S+1;
ADD(S,x1,an);ADD(x1,S,0);
ADD(S,y1,bn);ADD(y1,S,0);
ADD(x2,T,an);ADD(T,x2,0);
ADD(y2,T,bn);ADD(T,y2,0);
memset(dis,0,sizeof(dis));
memset(cnt,0,sizeof(cnt));
}
int main()
{
int i,j,k,x,y,z;
while(scanf("%d%d%d%d%d%d%d",&n,&a1,&a2,&an,&b1,&b2,&bn)!=EOF)
{
ans1=ans2=tot=0;
for(i=1;i<=n;i++)scanf("%s",&map[i][1]);
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)id[i][j]=++tot;
an<<=1;bn<<=1;
Build(a1,a2,b1,b2);
while(dis[S]<T+1)ans1+=SAP(S,1e9);
Build(a2,a1,b1,b2);
while(dis[S]<T+1)ans2+=SAP(S,1e9);
if(ans1==an+bn&&ans2==an+bn)puts("Yes");
else puts("No");
}
}