源向a1和b1连流量为2*an,2*bn的边,a2和b2向汇连流量为2*an,2*bn的边,其他边非危桥连inf,危桥连2的边,跑最大流,但是这时满流不一定有解,因为可能有a1流到b2的流这样,所以把b1,b2反过来重构图再跑一次最大流,若能满流则有解。证明:假设第一次a1流了x的流到b2,第二次的时候由于是无向图,a1到a2流还是2*an-x,那么a1到b1是x,所以有x的流是b1-a1-b2,所以一样能流到b2。。
#include<cstdio>
#include<iostream>
#define N 60
#define inf 0x3ffffff
using namespace std;
struct edge{
int e,f,next;
}ed[N*N*2];
int n,i,j,a1,a2,an,b1,b2,bn,ne,nd,t,a[N],d[N],que[N],u[N],mp[N][N];
char s[N];
void add(int s,int e,int f)
{
ed[++ne].e=e;ed[ne].f=f;
ed[ne].next=a[s];a[s]=ne;
}
bool bfs(int s,int t)
{
int i,j,head=1,tail=1,get;
for (i=0;i<=nd;i++) u[i]=d[i]=0;
u[s]=1;que[1]=s;
while (head<=tail)
{
get=que[head++];
for (j=a[get];j;j=ed[j].next)
if (ed[j].f&&!u[ed[j].e])
{
d[ed[j].e]=d[get]+1;
u[ed[j].e]=1;
que[++tail]=ed[j].e;
}
}
return d[t]!=0;
}
int extend(int x,int minf,int t)
{
if (x==t) return minf;
int f=minf,del,j;
for (j=a[x];j;j=ed[j].next)
if (ed[j].f&&d[ed[j].e]==d[x]+1)
{
del=extend(ed[j].e,min(minf,ed[j].f),t);
ed[j].f-=del;ed[j^1].f+=del;
minf-=del;
if (!minf) break;
}
if (f==minf) d[x]=0;
return f-minf;
}
int dinic(int s,int t)
{
int ans=0;
while (bfs(s,t)) ans+=extend(s,inf,t);
return ans;
}
void build()
{
ne=1;
for (int i=0;i<=nd;i++) a[i]=0;
add(0,a1,2*an);add(a1,0,0);
add(0,b1,2*bn);add(b1,0,0);
add(nd,a2,0);add(a2,nd,2*an);
add(nd,b2,0);add(b2,nd,2*bn);
for (int i=1;i<=n;i++)
for (int j=i+1;j<=n;j++)
if (mp[i][j]) add(i,j,mp[i][j]),add(j,i,mp[i][j]);
}
int main()
{
while (scanf("%d%d%d%d%d%d%d",&n,&a1,&a2,&an,&b1,&b2,&bn)!=EOF)
{
nd=n+1;a1++;a2++;b1++;b2++;
for (i=1;i<=n;i++)
{
scanf("%s",s+1);
for (j=i+1;j<=n;j++)
if (s[j]=='O') mp[i][j]=2;else if (s[j]=='N') mp[i][j]=inf;else mp[i][j]=0;
}
build();
t=dinic(0,nd);
if (t<2*an+2*bn) printf("No\n");
else
{
swap(b1,b2);
build();
t=dinic(0,nd);
if (t<2*an+2*bn) printf("No\n");else printf("Yes\n");
}
}
}