网络流—最大流(Edmond-Karp算法)
一、含义
从源点到经过的所有路径的最终到达汇点的所有流量和
例如:

在这个图中求源点1,到汇点4的最大流。答案为50,其中1->2->4为20 ;1->4为20 ;1->2->3->4为10;总和为20+20+10=50。
二、EK算法的核心
反复寻找源点s到汇点t之间的增广路径,若有,找出增广路径上每一段[容量-流量]的最小值delta,若无,则结束。
在寻找增广路径时,可以用BFS来找,并且更新残留网络的值(涉及到反向边)。
而找到delta后,则使最大流值加上delta,更新为当前的最大流值。
对于BFS找增广路:
1. flow[1]=INF,pre[1]=0;
源点1进队列,开始找增广路,
capacity[1][2]=40>0,则flow[2]=min(flow[1],40)=40;
capacity[1][4]=20>0,则flow[4]=min(flow[1],20)=20;
capacity[2][3]=30>0,则flow[3]=min(folw[2]=40,30)=30;
capacity[2][4]=30,但是pre[4]=1(已经在capacity[1][4]这遍历过4号点了)
capacity[3][4].....
当index=4(汇点),结束增广路的寻找
传递回increasement(该路径的流),利用前驱pre寻找路径
路径也自然变成了这样:

2.flow[1]=INF,pre[1]=0;
源点1进队列,开始找增广路,
capacity[1][2]=40>0,则flow[2]=min(flow[1],40)=40;
capacity[1][4]=0!>0,跳过
capacity[2][3]=30>0,则flow[3]=min(folw[2]=40,30)=30;
capacity[2][4]=30,pre[4]=2,则flow[2][4]=min(flow[2]=40,20)=20;
capacity[3][4].....
当index=4(汇点),结束增广路的寻找
传递回increasement(该路径的流),利用前驱pre寻找路径
图也被改成

接下来同理

这就是最终完成的图,最终sumflow=20+20+10=50(这个就是最大流的值)
PS,为什么要有反向边呢?

我们第一次找到了1-2-3-4这条增广路,这条路上的delta值显然是1。于是我们修改后得到了下面这个流。(图中的数字是容量)

这时候(1,2)和(3,4)边上的流量都等于容量了,我们再也找不到其他的增广路了,当前的流量是1。
但这个答案明显不是最大流,因为我们可以同时走1-2-4和1-3-4,这样可以得到流量为2的流。
那么我们刚刚的算法问题在哪里呢?问题就在于我们没有给程序一个”后悔”的机会,应该有一个不走(2-3-4)而改走(2-4)的机制。那么如何解决这个问题呢?回溯搜索吗?那么我们的效率就上升到指数级了。
而这个算法神奇的利用了一个叫做反向边的概念来解决这个问题。即每条边(I,j)都有一条反向边(j,i),反向边也同样有它的容量。
我们直接来看它是如何解决的:
在第一次找到增广路之后,在把路上每一段的容量减少delta的同时,也把每一段上的反方向的容量增加delta。即在Dec(c[x,y],delta)的同时,inc(c[y,x],delta)
我们来看刚才的例子,在找到1-2-3-4这条增广路之后,把容量修改成如下

这时再找增广路的时候,就会找到1-3-2-4这条可增广量,即delta值为1的可增广路。将这条路增广之后,得到了最大流2。

那么,这么做为什么会是对的呢?我来通俗的解释一下吧。
事实上,当我们第二次的增广路走3-2这条反向边的时候,就相当于把2-3这条正向边已经是用了的流量给”退”了回去,不走2-3这条路,而改走从2点出发的其他的路也就是2-4。(有人问如果这里没有2-4怎么办,这时假如没有2-4这条路的话,最终这条增广路也不会存在,因为他根本不能走到汇点)同时本来在3-4上的流量由1-3-4这条路来”接管”。而最终2-3这条路正向流量1,反向流量1,等于没有流量。
这就是这个算法的精华部分,利用反向边,使程序有了一个后悔和改正的机会。而这个算法和我刚才给出的代码相比只多了一句话而已。
至此,最大流Edmond-Karp算法介绍完毕。
三、代码:
/*poj1273*/
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <cstring>
#include <stdio.h>
#include <queue>
#define IO ios::sync_with_stdio(false);\
cin.tie();\
cout.tie();
using namespace std;
const int MAX=;
int map[][],flow[],pre[],n,m;
bool vis[];
int BFS()
{
int up;
queue<int> q;
vis[]=;
memset(pre,-,sizeof(pre));
memset(vis,,sizeof(vis));
for(int i=; i<=n; i++)
flow[i]=MAX;
q.push();
while(!q.empty())
{
up=q.front();
q.pop();
if(up==n)
break;
for(int i=; i<=n; i++)
{
if(!vis[i]&&map[up][i]>)
{
vis[i]=;
flow[i]=min(flow[up],map[up][i]);
pre[i]=up;
q.push(i);
}
}
}
if(!vis[n]||n==)
return -;
return flow[n];
}
int EK()
{
int d,maxflow=,up,down;
maxflow=;
while((d=BFS())!=-)
{
maxflow+=d;
down=n;
while(down!=)
{
up=pre[down];
map[up][down]-=d;
map[down][up]+=d;
down=up;
}
}
return maxflow;
}
int main()
{
while(~scanf("%d%d",&m,&n))
{
memset(map,,sizeof(map));
int a,b,c;
for(int i=; i<=m; i++)
{
scanf("%d%d%d",&a,&b,&c);
map[a][b]+=c;
}
printf("%d\n",EK());//输出从1到n号点的最大流
}
return ;
}
网络流—最大流(Edmond-Karp算法)的更多相关文章
- HDU1532 网络流最大流【EK算法】(模板题)
<题目链接> 题目大意: 一个农夫他家的农田每次下雨都会被淹,所以这个农夫就修建了排水系统,还聪明的给每个排水管道设置了最大流量:首先输入两个数n,m ;n为排水管道的数量,m为节点的数量 ...
- 网络流---最大流(Edmond-Karp算法)的学习
先上个代码,等有空补充详解 #include<iostream> #include<cstdio> #include<cstring> #include<cm ...
- 最大流算法之Ford-Fulkerson算法与Edmonds–Karp算法
引子 曾经很多次看过最大流的模板,基础概念什么的也看了很多遍.也曾经用过强者同学的板子,然而却一直不会网络流.虽然曾经尝试过写,然而即使最简单的一种算法也没有写成功过,然后对着强者大神的代码一点一点的 ...
- 网络流(一)——Edmonds Karp算法
首先是一些关于网络流的术语: 源点:即图的起点. 汇点:即图的终点. 容量:有向边(u,v)允许通过的最大流量. 增广路:一条合法的从源点流向汇点的路径. 网络流问题是在图上进行解决的,我们通常可以将 ...
- (通俗易懂小白入门)网络流最大流——EK算法
网络流 网络流是模仿水流解决生活中类似问题的一种方法策略,来看这么一个问题,有一个自来水厂S,它要向目标T提供水量,从S出发有不确定数量和方向的水管,它可能直接到达T或者经过更多的节点的中转,目前确定 ...
- [讲解]网络流最大流dinic算法
网络流最大流算法dinic ps:本文章不适合萌新,我写这个主要是为了复习一些细节,概念介绍比较模糊,建议多刷题去理解 例题:codevs草地排水,方格取数 [抒情一下] 虽然老师说这个多半不考,但是 ...
- 【最大流之ek算法】HDU1532 求最大流
本来是继续加强最短路的训练,但是遇到了一个最短路 + 最大流的问题,最大流什么鬼,昨天+今天学习了一下,应该对ek算法有所了解,凭借学习后的印象,自己完成并ac了这个最大流的模板题 题目大意:都是图论 ...
- 网络流(四)dinic算法
传送门: 网络流(一)基础知识篇 网络流(二)最大流的增广路算法 网络流(三)最大流最小割定理 网络流(四)dinic算法 网络流(五)有上下限的最大流 网络流(六)最小费用最大流问题 转自:http ...
- [数据结构]最大流之Ford-Fulkerson算法
本文主要讲解最大流问题的Ford-Fulkerson解法.可以说这是一种方法,而不是算法,因为它包含具有不同运行时间的几种实现.该方法依赖于三种重要思想:残留网络,增广路径和割. 在介绍着三种概念之前 ...
随机推荐
- three.js_camera相机
https://blog.csdn.net/yangnianbing110/article/details/51275927 文章地址
- Python3 反射及常用的方法
反射就是通过字符串映射或修改程序运行时的状态.属性.方法 有四个常用方法: hasattr(obj,name_str) 判断一个obj对象是否有对应name_str的方法 getattr(obj,na ...
- git服务器的简单搭建
安装git 安装git,参考:https://git-scm.com/book/zh/v1/%E8%B5%B7%E6%AD%A5-%E5%AE%89%E8%A3%85-Git 创建git仓库 使用ro ...
- 使用批处理方式从svn 检出DEMO
Branching in Subversion¶ FROM:https://dev.geogebra.org/trac/wiki/SubversionBranching Some people wan ...
- 查看wtmp(登陆信息的内容)
/var/log/wtmp文件的作用 /var/log/wtmp也是一个二进制文件,记录每个用户的登录次数和持续时间等信息. 查看方法: 可以用last命令输出当中内容: debi ...
- hdu 5877(树状数组+dfs)
Weak Pair Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total ...
- kali&BT安装好之后无法上网(包括Wifi)或者无法获得内网IP解决方法
大家都知道,要想进行内网渗透攻击,你必须要在那个内网里.但是大家在Vmware里安装kali的时候,大多数用户为了方便,未选择桥接模式,而是选择了使用与本机共享的IP网络当然,这样能上网,但是你的虚拟 ...
- 深入理解 WordPress 数据库中的用户数据 wp_user
WordPress 使用 wp_users 数据表存储用户的主要数据,该数据表结构类似于wp_posts 和 wp_comments 数据表,存储的是需要经常访问的用户数据,该数据表的结构以及该数据表 ...
- 完美解决wordpress邮件链接无效的问题
教程介绍:解决wordpress新用户注册邮件链接无效以及重新设置密码链接无效的问题 解决流程 案例一.用户注册 当用户注册站点时,用户会收到如下注册信: 当用户点击链接时,却发现链接无效: 仔细观察 ...
- Git & GitHub 学习
学习资料: Git版本控制软件结合GitHub从入门到精通常用命令学习手册:http://www.ihref.com/read-16369.html 官方中文手册:http://git-scm.com ...