有源汇有上下界最小流详解(loj117)
来源:互联网 发布:魔法王座神器7上8数据 编辑:程序博客网 时间:2024/06/05 03:02
例题链接
首先还是得吐槽一下题意。
题意是这样的:
求出一个流使得源点的总流出量等于汇点的总流入量,其他的点满足流量守恒,而且每条边的流量满足上界和下界限制。在这些前提下要求总流量最小。
解法:
没学过无源汇有上下界可行流的还是先学学吧
好像是有两种做法的。
做法1:
首先先求出可行流,按照上一篇博客的做法即可。
上一篇博客
很明显现在已经满足下界了,那么我们只需在残量网络上求出最小流即可。
此时需要理解反向边。
反向边的流量增加等价于正向边的的流量减少。
那么t到s的流就相当于s到t减少的流。
那么求出t到s的最大流就相当于s到t减少最多的流,那么剩下的就是最小流。
所以最后的答案就是可行流大小-t到s的最大流
然而我并没有用第一种做法(以后可能会补代码吧)
做法2:(其实我觉得做法1更容易理解)
建立超级源和超级汇之后呢。
先跑一次最大流。
然后t到s连一条无穷大的边。
再跑一次最大流。
最后的答案就是无穷大的边流过的流量。
有点难理解。
首先因为整个图满足流量平衡。
所以说t点流入的流量等于流出的流量。
那么他流出的流量只有那一条无穷大的边而已。
所以说最小流就是求那条边(无穷边)流过的流量尽量小而已。
所以说第一次流最大流的时候已经满足下界。那么满足下界能流的边已经流满。
所以残量网络剩下的最大流就会尽可能的小了。
大概就是这样吧。
代码实现:
#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<iostream>#include<cmath>using namespace std;typedef long long ll;const ll inf=1e10;int st,ed;struct node { int x,y,other,next; ll c;}a[1100000];int last[71000],len;int h[71000],list[71000];ll d[71000];void ins(int x,int y,ll c) { int k1,k2; len++;k1=len; a[len].x=x;a[len].y=y;a[len].c=c; a[len].next=last[x];last[x]=len; len++;k2=len; a[len].x=y;a[len].y=x;a[len].c=0; a[len].next=last[y];last[y]=len; a[k1].other=k2; a[k2].other=k1;}int head,tail;bool bfs() { memset(h,0,sizeof(h));h[st]=1; head=1;tail=2;list[1]=st; while(head!=tail) { int x=list[head]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(a[k].c>0&&h[y]==0) { h[y]=h[x]+1; list[tail++]=y; if(tail==ed+1) tail=1; } } head++; if(head==ed+1) head=1; } if(h[ed]==0) return false; return true;}ll findflow(int x,ll f){ if(x==ed) return f; ll s=0,t; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(h[y]==h[x]+1&&a[k].c>0&&s<f) { t=findflow(y,min(a[k].c,f-s)); a[k].c-=t;a[a[k].other].c+=t; s+=t; } } if(s==0) h[x]=0; return s;}ll Dinic(){ ll ans=0; while(bfs()==true) ans+=findflow(st,inf); return ans;}int main(){ int n,m,s,t; scanf("%d%d%d%d",&n,&m,&s,&t); len=0;memset(last,0,sizeof(last)); for(int i=1;i<=m;i++) { int x,y;ll shang,xia; scanf("%d%d%lld%lld",&x,&y,&xia,&shang); ins(x,y,shang-xia); d[x]-=xia;d[y]+=xia; } st=n+1;ed=st+1; for(int i=1;i<=n;i++) { //满足流量平衡建边,详情见无源汇有上下界可行流 if(d[i]>0) ins(st,i,d[i]); if(d[i]<0) ins(i,ed,-d[i]); } ll sum=Dinic(); //先跑一次最大流 ins(t,s,inf); //建无穷边 sum+=Dinic(); //再跑一次最大流 bool bk=true; for(int k=last[st];k;k=a[k].next) { //判断是否有可行流 if(a[k].c>0) { bk=false;break; } } if(bk==false) printf("please go home to sleep\n"); else printf("%lld\n",a[len].c); //最后一条建的是无穷大的那条边。所以它的反向边流量就是它正向边所流过的流量 return 0;}
最后我又想吐槽一下。
loj的评测机说我第8个点超时了。结果我在本机上秒过。
有一点点恶心。。
阅读全文
0 0
- 有源汇有上下界最小流详解(loj117)
- loj117 有源汇有上下界最小流
- loj117 有源汇有上下界最小流(如题)
- sgu 176 Flow construction(有源汇有上下界最小流)
- bzoj2502 清理雪道(有源汇有上下界最小流)
- LOJ#117 有源汇有上下界最小流
- 有源汇有上下界最大流详解(loj116)
- sgu 176 有源汇有上下界的最小流模板题
- 【有源汇有上下界最小流】SGU-176 Flow constructions
- SGU 176 有源汇有上下界最小流(模板)
- SGU 176 Flow construction 有源汇有上下界的最小流
- 有源汇点有上下界的最小流(电路问题)
- hust 1342 - Cheat Secretly(有源汇有上下界的最小流)
- poj 3801 Crazy Circuits (有源汇有上下界的最小流)
- [BZOJ2502]清理雪道(有源汇有上下界的最小流)
- bzoj4200 [Noi2015]小园丁与老司机(dp+记录路径+有源汇有上下界最小流)
- bzoj3876 [Ahoi2014&Jsoi2014]支线剧情(有源汇有上下界最小费用流)
- bzoj2055 80人环游世界(有源汇有上下界最小费用流)
- Linux 使用selenium chrome实现爬虫的两个坑
- unrecognized Windows Sockets error: 10106: create
- Composer安装Thinkphp5
- 【福分系统】MUI日期控件
- ios-Swift中解除循环引用的三种方式
- 有源汇有上下界最小流详解(loj117)
- 235. Lowest Common Ancestor of a Binary Search Tree
- 斯坦福2016论文 使用Bloom Filters进行大规模以图搜视频
- Densely Connected Convolutional Networks(DenseNet)
- [数位DP] BZOJ1190. [HNOI2007]梦幻岛宝珠
- 如何学好3D游戏引擎编程
- POJ4124伟大的航线
- solr之Lucene全文搜索基本原理
- 后缀数组 倍增法模板