2189. 有源汇上下界最大流

题目链接

2189. 有源汇上下界最大流

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

给定源点 S 和汇点 T,求源点到汇点的最大流。

输入格式

第一行包含四个整数 n,m,S,T

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

点编号从 1n

输出格式

输出一个整数表示最大流。

如果无解,则输出 No Solution

数据范围

1n202,
1m9999,
1a,bn,
0cd105

输入样例:

10 15 9 10 9 1 17 18 9 2 12 13 9 3 11 12 1 5 3 4 1 6 6 7 1 7 7 8 2 5 9 10 2 6 2 3 2 7 0 1 3 5 3 4 3 6 1 2 3 7 6 7 5 10 16 17 6 10 10 11 7 10 14 15

输出样例:

43

解题思路

最大流,有源汇上下界最大流

不妨先找有源汇上下界可行流,同无源汇上下界可行流一样,可以先建立两个虚拟节点 S,T,多减的多加的可以通过虚拟节点补偿,且达到满流(即最大流)时说明找到一个可行流,但原图有源汇 s,t,这样的 s,t 两个节点流量不守恒,但可以从 ts 建立一条容量足够大的边,这样两点的流量就能守恒,ts忽略这条边后,流网络的所有边都满足上下界要求,所以这时忽略这条边仍然是流网络的一个可行流,而且由 s 点的流量守恒,此时 ts 的流量正好等于残余网络的 st 的可行流加上所有需要补充的下界,其数值等于原流网络的可行流
现在求解有源汇上下界最大流,一个可能可行的操作即先删除 ts 的边然后在原残留网络的基础上跑一遍 st 的最大流,即将 st 的残余网络完全榨干,但是需要是 st 的残余网络才行,而现在这个网络却是 ST 的残余网络,残余网络不同可行流不能直接相加减,但原流网络的一个可行流对应现流网络下满流的 st 的可行流,即所有与 ST 相关的边都满流了,在满流状态下,要求 st 达到最大流,而在现残余网络中求解 st 的最大流时并不会退流或引流到 ST,即榨干 st 的流量后 ST 相关的边仍然满流,此时对应原流网络中 st 的最大流,stts现在的 ts 的边在原流网络中是不存在的,求解最大流时可能会有一部分流量在这条边上,所以需要删去,保证所求解的最大流在要求的边上

  • 时间复杂度:O(n2m)

代码

// Problem: 有源汇上下界最大流 // Contest: AcWing // URL: https://www.acwing.com/problem/content/2191/ // 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=205,M=(N+10000)*2,inf=1e9; int n,m,S,T,s,t,C[N]; int h[N],e[M],ne[M],f[M],idx; int d[N],cur[N],q[N],hh,tt; 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); q[0]=S; cur[S]=h[S]; tt=hh=d[S]=0; 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]) { cur[x]=i; int y=e[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 flow=0,res=0; while(bfs())while(flow=dfs(S,inf))res+=flow; return res; } int main() { memset(h,-1,sizeof h); scanf("%d%d%d%d",&n,&m,&s,&t); for(int i=1;i<=m;i++) { int a,b,c,d; scanf("%d%d%d%d",&a,&b,&c,&d); add(a,b,d-c); C[a]-=c,C[b]+=c; } S=0,T=n+1; int tot=0; for(int i=1;i<=n;i++) if(C[i]>0)tot+=C[i],add(S,i,C[i]); else if(C[i]<0) add(i,T,-C[i]); add(t,s,inf); if(tot!=dinic())puts("No Solution"); else { int res=f[idx-1]; f[idx-1]=f[idx-2]=0; S=s,T=t; printf("%d\n",res+dinic()); } return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16925505.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(94)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示