[BZOJ3504]CQOI2014危桥|最大流

源向a1b1连流量为2*an2*bn的边,a2b2向汇连流量为2*an2*bn的边,其他边非危桥连inf,危桥连2的边,跑最大流,但是这时满流不一定有解,因为可能有a1流到b2的流这样,所以把b1b2反过来重构图再跑一次最大流,若能满流则有解。证明:假设第一次a1流了x的流到b2,第二次的时候由于是无向图,a1a2流还是2*an-x,那么a1b1x,所以有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");
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值