今天是2017/5/10,DCDCBigBig的第三篇博文

这段时间先把图论的一些算法复习一下,过段时间再搞数据结构吧。。。

最大流

基本概念

最大流问题(Maximum Flow Problem)是一种组合最优化问题,是网络流的基础。把问题抽象成一个有向图,从源点到汇点的每一条边都有一个最大容量,指这条边可以流过的流量最大值。问题要求的就是从源点到汇点的最大流量。注意和最长路的区别在于,它的流量可以通过多个路径流到汇点。
在求解问题之前,我们先来认识一些概念;
容量网络:我们刚才说的有向图G,即每条边都有一个最大容量的网络;
弧:就是网络中的边;
弧分四类:(设有一条弧流量为h(u,v),最大容量为c)
1,饱和弧,即h(u,v)= c;
2,非饱和弧,即h(u,v)< c;
3,非零弧,即h(u,v)< 0;
4,零弧,即h(u,v)= 0;
流量:一条弧实际所流过的流量;
可行流:满足条件1和2的一个网络流f:
1,流量限制,即每条弧的流量不能超过最大容量;
2,平衡条件限制,即每条弧流入的流量一定等于它流出的流量;
(特别地,如果一个网络上所有流量均为0,则称之为零流)
链:即从点u到u1,u1到u2,……,un到v的一条序列,其中每两个相邻的点都要连有一条弧,设L是网络G中一条从源点S到汇点T的链,则约定S到T的方向为正方向,但链中的弧方向不一定要和正方向相同。我们称链中和正方向相同的弧为正向弧,反之为反向弧;
增广路:设f是G中的一个可行流,设L是从S至T的一条链,若:
L中所有正向弧均为非饱和弧,且所有反向弧均为非零弧,
那么这条链就称为f的一条增广路,沿着增广路改进的操作叫做增广
残留容量:即在当前的可行流中弧h(u,v)的最大容量c减去已流流量f(u,v)的残余流量,记为su(u,v);
残余网络:即残余容量组成的网络,设残余网络G’,则对于G中的每一条弧h(u,v),若它是一条非饱和弧,则在G’中有一条弧h’(u,v),其最大容量c’(u,v)=c(u,v)-h(u,v),若它是一条非零弧,则在G’中有一条弧h”(v,u),其容量为c(u,v)。

问题求解

解决最大流有很多种解法,如EK、Isap、FF等,不过最有名的(主要是我们神圣的陈老师讲了的)就是dinic算法,我们今天也只介绍这一种,其他的有兴趣的童鞋可以自行百度。

dinic

学习dinic之前,我们先引入一个概念:层次图;
层次图就是分层图,一个点到源点的最短距离就叫做它的“层次”,分层图中“层次”相同的点为一层。建立分层图有一个好,就是同一层的点不可能在同一条链中,这样在找增广路时可以省去很多重复计算。
所以dinic的基本思路就是不断地根据残余网络建立层次图,然后在层次图中dfs找增广路,直到无法增广为止,这样运行速度就会快很多。下面就来看一下具体的解决精髓:反向边

反向边

我们为什么要反向边呢?看下面的一个例子(源点是1,汇点是4):

我们可以很快的找到一个增广路1-2-3-4,增加流量为1,得到流如下:

可这时我们发现,弧(1,2)和(3,4)都已经是饱和弧,再也找不到增广路了,而最大流却明显不是1,是2,即同时走1-2-4和1-3-4。那么问题出在哪里了呢?
问题就是我们没有给算法“后悔”的机会,它找完一个增广路后就没有改变原来2-3-4而走2-4的操作。那么怎么解决呢?暴力回溯?等着TLE吧。。。
所以dinic(其实所有最大流的算法都是)用了一个非常神奇的东东来解决这个问题:反向边。
反向边,就是对于网络G中的每条弧h(u,v)都加入一条反向弧h(v,u),初始最大容量为c(u,v)。
而在每次增广的时候,就将增广路上每一段容量减少n,同时将反向弧容量增加n。
继续看刚才的例子,加入反向边后,网络流修改成如下:

那么此时再找,就可以找到1-3-2-4这条增广路,最终最大流量为2。

可是这样做为什么是对的呢?因为当我们第二次增广走过反向边3-2时就相当于把2-3这条正向边所用的流量给“退流”了,即不走2-3-4而改走从2出发的其它路,即2-4,最终流量也是一样的。(注意2-4是必定存在的,因为如果没有2-4的话就不会有1-3-2-4这条增广路)同时3-4的流量就变到了1-3-4这条路上,2-3这条边正向反向流量均为1,就相互抵消了,相当于没有流量。
这就是反向边的基本思想,它通过“退流”的方式,给了算法后悔的机会。下面直接上代码:

代码(POJ1273——模板题)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
struct edge{int y,r,next,op;
}a[401];
int head[201],q[5001],level[201],ans=0,x,y,z,n,m,vs,vt,tot=0;
void add(int x,int y,int z){a[++tot].y=y;a[tot].r=z;a[tot].next=head[x];head[x]=tot;a[tot].op=tot+1;a[++tot].y=x;a[tot].r=0;a[tot].next=head[y];head[y]=tot;a[tot].op=tot-1;
}
bool bfs(){int u,tmp,v,f=1,r=1;memset(level,0,sizeof(level));q[f]=vs;level[vs]=1;while(f<=r){v=q[f];tmp=head[v];while(tmp!=-1){u=a[tmp].y;if(a[tmp].r&&!level[u]){level[u]=level[v]+1;q[++r]=u;if(u==vt)return true;}tmp=a[tmp].next;}f++;}return false;
}
int dfs(int v,int num){int value,flow,tmp,u,ans=0;if(v==vt||!num)return num;tmp=head[v];while(tmp!=-1){u=a[tmp].y;value=a[tmp].r;if(level[u]==level[v]+1){flow=dfs(u,min(value,num));if(flow){a[tmp].r-=flow;a[a[tmp].op].r+=flow;ans+=flow;num-=flow;if(!num)break;}}tmp=a[tmp].next;}return ans;
}
int main(){scanf("%d%d",&n,&m);vs=1;vt=m;memset(head,255,sizeof(head));for(int i=1;i<=n;i++){scanf("%d%d%d",&x,&y,&z);add(x,y,z);}while(bfs()){ans+=dfs(1,2147483647);}printf("%d",ans);return 0;
}

时间复杂度

dinic算法算是所有解决最大流问题的算法中效率最高的一种,证明比较复杂,这里直接给出复杂度:
最坏情况时间复杂度:O(V^2*E);
期望时间复杂度:O(min(V^3/2,E^1/2)*E);
最好时间复杂度(二分图):O(sqrt(V)*E);
一般来说,dinic的时间复杂度比这个丧心病狂的最坏情况要好得多,都在期望值左右,所以不要被吓到了。。。哦对了,dinic算法还可以跑二分图匹配,这个下次再讲。

这次复习的过程中参考了x_y_q_的博文(http://blog.csdn.net/x_y_q_/article/details/51999466),并盗了图。十分感谢!

ps:啊。。。终于写完了,本来还想写费用流的,然而由于本菜懒癌发作,整整拖到17号。。。无奈就只能先结束了这篇,等一下再写费用流吧。。。


(网络流)最大流复习相关推荐

  1. POJ - 3614 Sunscreen(贪心/二分图最大匹配-多重匹配/网络流-最大流)

    题目链接:点击查看 题目大意:给出n头奶牛,奶牛们现在要晒太阳,每头奶牛需要[l,r]区间内的光照强度,现在有m种防晒霜,每种防晒霜可以让奶牛接受到val数值的光照强度,然后每种防晒霜只有num个,现 ...

  2. 【bzoj1532】[POI2005]Kos-Dicing 二分+网络流最大流

    题目描述 Dicing 是一个两人玩的游戏,这个游戏在Byteotia非常流行. 甚至人们专门成立了这个游戏的一个俱乐部. 俱乐部的人时常在一起玩这个游戏然后评选出玩得最好的人.现在有一个非常不走运的 ...

  3. 【图论】网络流——最大流和最小费用流

    [图论]网络流--最大流和最小费用流 文章目录 [图论]网络流--最大流和最小费用流 1. 最大流问题 1.1 基本概念 1.2 寻求最大流的算法(Ford-Fulerson) 1.3 matlab求 ...

  4. 网络流最大流初步-Push–relabel maximum flow algorithm

    简介 做网络流最大流的题,常用的算法就是Dinic's algorithm.时间复杂度为,通常由于出题人水平较低,几乎能过所有的题.功利地看,这样就没问题了.但是,站在追求真(zhuang)理(B)的 ...

  5. (通俗易懂小白入门)网络流最大流——EK算法

    网络流 网络流是模仿水流解决生活中类似问题的一种方法策略,来看这么一个问题,有一个自来水厂S,它要向目标T提供水量,从S出发有不确定数量和方向的水管,它可能直接到达T或者经过更多的节点的中转,目前确定 ...

  6. 网络流——最大流EK算法讲解

    网络流--最大流EK算法讲解 好了,这是第二篇博客了,如第一篇所述,来讲一讲刚刚理解的网络流.因为本人只会EK算法,所以先讲这个算法.(我会去补知识点的!!!) 什么是网络流??? 读者们刚接触这个知 ...

  7. 图论-网络流⑦-费用流解题

    图论-网络流⑦-费用流解题 上一篇:图论-网络流⑥-费用流 下一篇:图论-网络流⑧-有上下界的网络流 参考文献: https://www.luogu.com.cn/blog/user9012/solu ...

  8. POJ - 1459 Power Network(网络流-最大流)

    题目链接:点击查看 题目大意:题意属实恶心,借用别的大佬的题意: 题目描述 一个电网包含一些结点(电站.消费者.调度站),这些结点通过电线连接.每个结点 uu 可能被供给 s(u) 的电能, s(u) ...

  9. 【HDU - 3081】Marriage Match II(网络流最大流,二分+网络流)

    题干: Presumably, you all have known the question of stable marriage match. A girl will choose a boy; ...

最新文章

  1. 【分布式共识三】拜占庭将军问题----书面协议
  2. 资讯丨NVIDIA自造AI超级计算机:轻松进入世界前五
  3. windows不能在启动oracle,Windows不能在当地电脑启动OracleDBConsoleorcl
  4. Google Maps打开出现internal error错误
  5. .NET MVC 保存Session值,6位数验证码
  6. python之路day4_python之路day4
  7. rdd.foreach(print)报错SyntaxError: invalid syntax
  8. 二分查找法(Java实现)
  9. 传统蓝牙和Bluz低功耗蓝牙的区别
  10. opencv findcontour查找最大的内轮廓
  11. 5G技术将如何改变我们的世界
  12. Mybatis 插入与批量插入以及多参数批量删除
  13. Matlab 官网培训 - 大型项目-风力发电机数据模型构建-Catching the Wind
  14. codevs1253 超级市场(dp)
  15. 在vs2010中运行guge.cpp(SkeletonDepth)的时候程序是网上的,可是总是提示我没有KinectUNI.lib。
  16. python查火车票_Python查询火车票(三)
  17. 三元运算符语法格式php,php中三元运算符用法详解
  18. 2019年春季学期《C语言程序设计II》助教注意事项
  19. Justinmind破解
  20. C语言有趣的代码大全,分享一段有趣的小代码

热门文章

  1. webstorm(二):拼写warning
  2. Android Camera驱动相关参数学习
  3. 资源分享 | 平面设计 | 平面设计视频教程
  4. 查看网页加密密码超简单
  5. C++ 龙的传人游戏(正版)
  6. 配置邮件服务器(SMTP简单步骤)
  7. 收藏:谨以此曲献给MJ—It's Not Easy To Be Me想做自己不易
  8. csharp进阶练习题:圣诞礼物计算器【难度:2级】--景越C#经典编程题库,不同难度C#练习题,适合自学C#的新手进阶训练
  9. java编程如何算圆的面具,Java实现人物拼图游戏│附代码
  10. 广东20213 证书高考成绩查询,广东高中学业水平考试成绩查询系统