[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");
		}
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章