2188. 无源汇上下界可行流

题目链接

2188. 无源汇上下界可行流

给定一个包含 \(n\) 个点 \(m\) 条边的有向图,每条边都有一个流量下界和流量上界。

求一种可行方案使得在所有点满足流量平衡条件的前提下,所有边满足流量限制。

输入格式

第一行包含两个整数 \(n\)\(m\)

接下来 \(m\) 行,每行包含四个整数 \(a,b,c,d\) 表示点 \(a\)\(b\) 之间存在一条有向边,该边的流量下界为 \(c\),流量上界为 \(d\)

点编号从 \(1\)\(n\)

输出格式

如果存在可行方案,则第一行输出 YES,接下来 \(m\) 行,每行输出一个整数,其中第 \(i\) 行的整数表示输入的第 \(i\) 条边的流量。

如果不存在可行方案,直接输出一行 NO

如果可行方案不唯一,则输出任意一种方案即可。

数据范围

\(1 \le n \le 200\),
\(1 \le m \le 10200\),
\(1 \le a,b \le n\),
\(0 \le c \le d \le 10000\)

输入样例1:

4 6
1 2 1 3
2 3 1 3
3 4 1 3
4 1 1 3
1 3 1 3
4 2 1 3

输出样例1:

YES
1
2
3
2
1
1

输入样例2:

4 6
1 2 1 2
2 3 1 2
3 4 1 2
4 1 1 2
1 3 1 2
4 2 1 2

输出样例2:

NO

解题思路

最大流,无源汇上下界可行流

建图:对于一个可行流,\(c_1\leq f\leq c_2\),即 \(0\leq f-c_1\leq c_2-c_1\),满足流量限制,但对于一个节点来说,不一定满足流量守恒,即不一定有 \(\sum c_{入}= \sum c_{出}\),可以另外建立一个源点和汇点,将不满足该要求的点多的(由于是 \(f-c_1\))用源点连向该点且容量为 \(\sum c_{入}- \sum c_{出}\) 的边,否则该点连向汇点且容量为 \(\sum c_{出}-\sum c_{入}\) 的边,且要求最大流满流

  • 时间复杂度:\(O(n^2m)\)

代码

// Problem: 无源汇上下界可行流
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/2190/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=21000,M=205,inf=0x3f3f3f3f;
int n,m,C[M],s,t;
int h[M],e[N],f[N],ne[N],idx,down[N];
int q[M],hh,tt,cur[N],d[N];
void add(int a,int b,int c)
{
	e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++;
	e[idx]=a,f[idx]=0,ne[idx]=h[b],h[b]=idx++;
}
bool bfs()
{
	memset(d,-1,sizeof d);
	d[s]=hh=tt=0;
	cur[s]=h[s];
	q[0]=s;
	while(hh<=tt)
	{
		int x=q[hh++];
		for(int i=h[x];~i;i=ne[i])
		{
			int y=e[i];
			if(d[y]==-1&&f[i])
			{
				d[y]=d[x]+1;
				cur[y]=h[y];
				if(y==t)return true;
				q[++tt]=y;
			}
		}
	}
	return false;
}
int dfs(int x,int limit)
{
	if(x==t)return limit;
	int flow=0;
	for(int i=cur[x];~i&&flow<limit;i=ne[i])
	{
		int y=e[i];
		cur[x]=i;
		if(d[y]==d[x]+1&&f[i])
		{
			int t=dfs(y,min(f[i],limit-flow));
			if(!t)d[y]=-1;
			f[i]-=t,f[i^1]+=t,flow+=t;
		}
	}
	return flow;
}
int dinic()
{
	int res=0,flow;
	while(bfs())while(flow=dfs(s,inf))res+=flow;
	return res;
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(h,-1,sizeof h);
    for(int i=1;i<=m;i++)
    {
    	int a,b,c,d;
    	scanf("%d%d%d%d",&a,&b,&c,&d);
    	d-=c;
    	down[idx]=c,add(a,b,d);
    	C[a]-=c,C[b]+=c;
    }
    s=0,t=n+1;
    int res=0;
    for(int i=1;i<=n;i++)
    	if(C[i]>0)res+=C[i],add(s,i,C[i]);
    	else
    		add(i,t,-C[i]);
    if(res!=dinic())puts("NO");
    else
    {
    	puts("YES");
    	for(int i=0;i<m*2;i+=2)
    		printf("%d\n",f[i^1]+down[i]);
    }
    return 0;
}
posted @ 2022-08-07 18:09  zyy2001  阅读(67)  评论(0编辑  收藏  举报