有上下界的网络流

传送门115
传送门116
传送门117

LOJ115 无源汇有上下界可行流

题解:
一时半会不想写题于是打算搞事情 | 谁说我这是正儿八经给别人看了
明明学这玩意过去这么久了怎么现在才开始把板子放上来啊
很容易想到可以把每条边的容量变成up-low。但是因为这之后流量不守恒,再搞一个超级源点s和超级汇点t,然后记录一下每个点的val[i]=in[i](入流下界之和)-out[i](出流下界之和)。
当val[i]>0,s到i连边,容量val[i];当val[i]<0,i到t连边,容量-val[i]。
然后对s,t求最大流。当从s出去的边全部满流时有解。

代码:

#include
#include
#include
#define maxn 205
#define maxm 50005
#define INF 0x3f3f3f3f
using namespace std;
int n,m,s,t,val[maxn],flow,dist[maxn],cur[maxn],head[maxn],ncnt,ans[maxm],L[maxm];
struct node { int v,i,cap,nxt; } e[maxm];
void addedge(int u,int v,int i,int cap)
{
	ncnt++;
	e[ncnt].v=v,e[ncnt].cap=cap,e[ncnt].i=i,e[ncnt].nxt=head[u];
	head[u]=ncnt;
}
void Add(int u,int v,int i,int w) { addedge(u,v,i,w); addedge(v,u,0,0); }
bool bfs()
{
	for(int i=0;i<=t;i++) dist[i]=-1,cur[i]=head[i];
	queue<int> q;
	dist[s]=0; q.push(s);
	while(!q.empty())
	{
		int u=q.front(); q.pop();
		for(int p=head[u];p;p=e[p].nxt)
		{
			int v=e[p].v;
			if(dist[v]>=0||!e[p].cap) continue;
			dist[v]=dist[u]+1; q.push(v);
		}
	}
	return dist[t]>=0;
}
int dfs(int u,int Cap)
{
	if(u==t||!Cap) return Cap;
	int flow=0;
	for(int &p=cur[u];p;p=e[p].nxt)
	{
		int v=e[p].v;
		if(dist[v]==dist[u]+1)
		{
			int f=dfs(v,min(e[p].cap,Cap));
			if(!f) continue;
			flow+=f,Cap-=f,e[p].cap-=f,e[p^1].cap+=f;
			if(!Cap) break;
		}
	}
	return flow;
}
void dinic()
{
	while(bfs()) flow+=dfs(s,INF);
}
int main()
{
	scanf("%d%d",&n,&m); ncnt=1;
	for(int i=1;i<=m;i++)
	{
		int u,v,l,r;
		scanf("%d%d%d%d",&u,&v,&l,&r);
		Add(u,v,i,r-l); val[u]-=l,val[v]+=l,L[i]=l;
	}
	s=0,t=n+1;
	for(int i=1;i<=n;i++)
		if(val[i]>0) Add(s,i,0,val[i]);
		else if(val[i]<0) Add(i,t,0,-val[i]);
	dinic();
	for(int p=head[s];p;p=e[p].nxt)
		if(e[p].cap) { printf("NO\n"); return 0; }
	for(int i=2;i<=ncnt;i++) ans[e[i].i]=e[i^1].cap;
	printf("YES\n");
	for(int i=1;i<=m;i++) printf("%d\n",ans[i]+L[i]);
}

LOJ116 有源汇有上下界最大流

题解:
语死早表示这玩意怎么可能是别人能看的
我们先跑一发可行流。
可以从t到s连一条容量INF的边,转化成无源汇有上下界最大流,那么跑完之后s到t的权值即为所求。
然后在残量网络上跑s-t最大流即可。
所求为二者之和。

代码:

#include
#include
#include
#define maxn 205
#define maxm 50005
#define INF 0x3f3f3f3f
using namespace std;
int n,m,s,t,val[maxn],flow,dist[maxn],cur[maxn],head[maxn],ncnt,ans[maxm],L[maxm],s0,t0;
struct node { int v,i,cap,nxt; } e[maxm];
void addedge(int u,int v,int cap)
{
	ncnt++;
	e[ncnt].v=v,e[ncnt].cap=cap,e[ncnt].nxt=head[u];
	head[u]=ncnt;
}
void Add(int u,int v,int w) { addedge(u,v,w); addedge(v,u,0); }
bool bfs()
{
	for(int i=0;i<=t;i++) dist[i]=-1,cur[i]=head[i];
	queue<int> q;
	dist[s]=0; q.push(s);
	while(!q.empty())
	{
		int u=q.front(); q.pop();
		for(int p=head[u];p;p=e[p].nxt)
		{
			int v=e[p].v;
			if(dist[v]>=0||!e[p].cap) continue;
			dist[v]=dist[u]+1; q.push(v);
		}
	}
	return dist[t]>=0;
}
int dfs(int u,int Cap)
{
	if(u==t||!Cap) return Cap;
	int flow=0;
	for(int &p=cur[u];p;p=e[p].nxt)
	{
		int v=e[p].v;
		if(dist[v]==dist[u]+1)
		{
			int f=dfs(v,min(e[p].cap,Cap));
			if(!f) continue;
			flow+=f,Cap-=f,e[p].cap-=f,e[p^1].cap+=f;
			if(!Cap) break;
		}
	}
	return flow;
}
void dinic()
{
	while(bfs()) flow+=dfs(s,INF);
}
int main()
{
	scanf("%d%d%d%d",&n,&m,&s0,&t0); ncnt=1;
	for(int i=1;i<=m;i++)
	{
		int u,v,l,r;
		scanf("%d%d%d%d",&u,&v,&l,&r);
		Add(u,v,r-l); val[u]-=l,val[v]+=l,L[i]=l;
	}
	s=0,t=n+1;
	for(int i=1;i<=n;i++)
		if(val[i]>0) Add(s,i,val[i]);
		else if(val[i]<0) Add(i,t,-val[i]);
	Add(t0,s0,INF);
	dinic();
	for(int p=head[s];p;p=e[p].nxt)
		if(e[p].cap) { printf("please go home to sleep\n"); return 0; }
	for(int i=1;i<=n;i++)
		for(int p=head[i];p;p=e[p].nxt)
			if(e[p].v==t||e[p].v==s) e[p].cap=e[p^1].cap=0;
	for(int p=head[s0];p;p=e[p].nxt)
		if(e[p].v==t0) { flow=e[p].cap,e[p].cap=e[p^1].cap=0; }
	s=s0,t=t0;
	dinic();
	printf("%d\n",flow);
}

LOJ117 有源汇有上下界最小流

题解:
求完可行流后跑t-s最大流,二者相减即为所求。

代码:

#include
#include
#include
#define maxn 50010
#define maxm 500005
#define LL long long
#define INF (LL)1e16
using namespace std;
int n,m,s,t,val[maxn],dist[maxn],cur[maxn],head[maxn],ncnt,ans[maxm],L[maxm],s0,t0;
LL flow;
struct node { int v,i,nxt; LL cap; } e[maxm];
void addedge(int u,int v,LL cap)
{
	ncnt++;
	e[ncnt].v=v,e[ncnt].cap=cap,e[ncnt].nxt=head[u];
	head[u]=ncnt;
}
void Add(int u,int v,LL w) { addedge(u,v,w); addedge(v,u,0); }
bool bfs()
{
	for(int i=0;i<=n+1;i++) dist[i]=-1,cur[i]=head[i];
	queue<int> q;
	dist[s]=0; q.push(s);
	while(!q.empty())
	{
		int u=q.front(); q.pop();
		for(int p=head[u];p;p=e[p].nxt)
		{
			int v=e[p].v;
			if(dist[v]>=0||!e[p].cap) continue;
			dist[v]=dist[u]+1; q.push(v);
		}
	}
	return dist[t]>=0;
}
LL dfs(int u,LL Cap)
{
	if(u==t||!Cap) return Cap;
	LL flow=0;
	for(int &p=cur[u];p;p=e[p].nxt)
	{
		int v=e[p].v;
		if(dist[v]==dist[u]+1)
		{
			LL f=dfs(v,min(e[p].cap,Cap));
			if(!f) continue;
			flow+=f,Cap-=f,e[p].cap-=f,e[p^1].cap+=f;
			if(!Cap) break;
		}
	}
	return flow;
}
void dinic()
{
	while(bfs()) flow-=dfs(s,INF);
}
int main()
{
	scanf("%d%d%d%d",&n,&m,&s0,&t0); ncnt=1;
	for(int i=1;i<=m;i++)
	{
		int u,v,l,r;
		scanf("%d%d%d%d",&u,&v,&l,&r);
		Add(u,v,r-l); val[u]-=l,val[v]+=l,L[i]=l;
	}
	s=0,t=n+1;
	for(int i=1;i<=n;i++)
		if(val[i]>0) Add(s,i,val[i]);
		else if(val[i]<0) Add(i,t,-val[i]);
	Add(t0,s0,INF);
	dinic();
	for(int p=head[s];p;p=e[p].nxt)
		if(e[p].cap) { printf("please go home to sleep\n"); return 0; }
	for(int i=1;i<=n;i++)
		for(int p=head[i];p;p=e[p].nxt)
			if(e[p].v==t||e[p].v==s) e[p].cap=e[p^1].cap=0;
	for(int p=head[s0];p;p=e[p].nxt)
		if(e[p].v==t0) flow=e[p].cap,e[p].cap=e[p^1].cap=0;
	s=t0,t=s0;
	dinic();
	printf("%lld\n",flow);
}

你可能感兴趣的:(懵逼了半天终于AC,网络流)