有源汇有上下界最大流详解(loj116)
来源:互联网 发布:文明5 贸易网络 编辑:程序博客网 时间:2024/06/08 03:22
例题链接
首先吐槽一下放题人(我不知道是不是我理解错了什么。)
题目描述里就一个上下界然后就说要求最大流。。。
直接建上界然后跑最大流不就完了么??
实际上原题是这样的:
求出一个流使得源点的总流出量等于汇点的总流入量,其他的点满足流量守恒,而且每条边的流量满足上界和下界限制。在这些前提下要求总流量最大。
没学过无源汇有上下界可行流的看这里
可行流我不刚学完么。。想了想。。
上一题是无源汇的,而这道题是有源汇的。
那么我只要将他变成循环流就可以了嘛(其实就是变成无源汇而已)
那么从汇点到源点建一条流量无限的边那么这个图不就变成无源汇了嘛。
然后建一个超级源点和超级汇点。(st和ed)
按照上一题的d来连边。
如果d>0建一条st到i的边。
如果d<0建一条i到ed的边。
跟上一题一模一样(无源汇有上下界可行流)
然后判断一下从st出发的边是否满流(满流则有解,不满则无解)
因为第一次跑完最大流之后求得的是流满下界的流
那么图里还剩许多s到t的自由流。
所以剩下的把st和ed删掉。把与st和ed相连的边也删掉。
然后在剩下的图上跑一次从s到t的最大流即可。
那么最终答案就是流满下界的流+残余的自由流
代码实现:
#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<iostream>#include<cmath>using namespace std;int n,m,st,ed;struct node { int x,y,c,other,next;}a[41000];int last[210],len;int work[210],h[210],list[210];int d[21000],id[21000],chushi[21000];void ins(int x,int y,int c,int t) { 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;id[len]=t; len++;k2=len; a[len].x=y;a[len].y=x;a[len].c=0; a[len].next=last[y];last[y]=len;id[len]=0; 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;}int findflow(int x,int f){ if(x==ed) return f; int 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;}int Dinic(){ int ans=0; while(bfs()==true) ans+=findflow(st,999999999); 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));memset(id,0,sizeof(id)); memset(d,0,sizeof(d));memset(chushi,0,sizeof(chushi)); for(int i=1;i<=m;i++) { int x,y,shang,xia; scanf("%d%d%d%d",&x,&y,&xia,&shang); ins(x,y,shang-xia,i); d[x]-=xia;d[y]+=xia; } int llen=len;st=n+1;ed=st+1; for(int i=1;i<=n;i++) { //详情见无源汇有上下界可行流的题解 if(d[i]>0) ins(st,i,d[i],0); if(d[i]<0) ins(i,ed,-d[i],0); } ins(t,s,999999999,0); //把有源汇的图构建成无源汇。 int 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 { int ans=a[a[last[t]].other].c; //跑完最大流后每条边的反向边的流量就为流过该边的流量。那么看一下流过t的流量有多少。 for(int i=1;i<=len;i++) if(id[i]==0) //id等于0的边都是与st和ed相连的 a[i].c=0; last[st]=last[ed]=0; st=s;ed=t; //跑s到t的最大流 printf("%d\n",ans+Dinic()); } return 0;}
感觉网络流这个专题好像很强。运用蛮广泛的。最重要的问题还是要理解不同的题流量代表的是什么以及不同的题如何去构图。
阅读全文
0 0
- 有源汇有上下界最大流详解(loj116)
- loj116 有源汇有上下界最大流
- loj116 有源汇有上下界最大流(如题)
- bzoj3698 XWW的难题(有源汇有上下界最大流)
- 有源汇有上下界的最大流
- LOJ #116. 有源汇有上下界最大流
- 有源汇有上下界最小流详解(loj117)
- zoj 3229 有源汇有上下界的最大流模板题
- 【有源汇有上下界最大流】ZOJ-3229 Shoot the Bullet
- ZOJ 3229 Shoot the Bullet(有源汇有上下界的最大流)
- zoj 3229 Shoot the Bullet(有源汇有上下界的最大流)
- ZOJ 3229 Shoot the Bullet(有源汇有上下界最大流)
- zoj 3229 Shoot the Bullet (有源汇有上下界的最大流)
- bzoj 3698: XWW的难题 (有源汇有上下界的最大流)
- [BZOJ3698]XWW的难题(有源汇有上下界的最大流)
- zoj3229 有源汇上下界最大流
- ZOJ 3229 有源有汇上下界最大流
- 2个经典 zoj2314 无源汇有上下界最大流 并输出可行流 ZOJ3229 有源汇上下界最大流
- hdu 3038 How Many Answers Are Wrong——带权并查集
- Cannot create encoder for Option of Product type, because Product type is represented as a row
- 最短路之Floyd(弗洛伊德)算法
- ccf 201703-1分蛋糕
- webpack
- 有源汇有上下界最大流详解(loj116)
- 顺序表应用1:多余元素删除之移位算法
- 过滤器
- python坑路历程(一)
- CSS Mask 在WeGame新手引导的实践
- Maven配置环境变量
- web安全技术
- 魔法城市路径问题(腾讯2017校招笔试题)
- 将原始图片转换成TFRecord文件