最大流——EK算法
一、算法理论
【基本思想】
反复寻找源点s到汇点t之间的增广路径,若有,找出增广路径上每一段[容量-流量]的最小值delta,若无,则结束。
在寻找增广路径时,可以用BFS来找,并且更新残留网络的值(涉及到反向弧)。
而找到delta后,则使最大流值加上delta,更新为当前的最大流值。
【算法详解】

这么一个图,求源点1到汇点4的最大流。
由于我是通过模版真正理解ek的含义,所以先上代码,通过分析代码,来详细叙述ek算法。
#include <iostream>
#include <queue>
#include<string.h>
using namespace std;
#define arraysize 201
int maxData = 0x7fffffff;
int capacity[arraysize][arraysize]; //记录残留网络的容量
int flow[arraysize]; //标记从源点到当前节点实际还剩多少流量可用
int pre[arraysize]; //标记在这条路径上当前节点的前驱,同时标记该节点是否在队列中
int n,m;
queue<int> myqueue;
int BFS(int src,int des)
{
int i,j;
while(!myqueue.empty()) //队列清空
myqueue.pop();
for(i=1;i<m+1;++i)
{
pre[i]=-1;
}
pre[src]=0;
flow[src]= maxData;
myqueue.push(src);
while(!myqueue.empty())
{
int index = myqueue.front();
myqueue.pop();
if(index == des) //找到了增广路径
break;
for(i=1;i<m+1;++i)
{
if(i!=src && capacity[index][i]>0 && pre[i]==-1)
{
pre[i] = index; //记录前驱
flow[i] = min(capacity[index][i],flow[index]); //关键:迭代的找到增量
myqueue.push(i);
}
}
}
if(pre[des]==-1) //残留图中不再存在增广路径
return -1;
else
return flow[des];
}
int maxFlow(int src,int des)
{
int increasement= 0;
int sumflow = 0;
while((increasement=BFS(src,des))!=-1)
{
int k = des; //利用前驱寻找路径
while(k!=src)
{
int last = pre[k];
capacity[last][k] -= increasement; //改变正向边的容量
capacity[k][last] += increasement; //改变反向边的容量
k = last;
}
sumflow += increasement;
}
return sumflow;
}
int main()
{
int i,j;
int start,end,ci;
while(cin>>n>>m)
{
memset(capacity,0,sizeof(capacity));
memset(flow,0,sizeof(flow));
for(i=0;i<n;++i)
{
cin>>start>>end>>ci;
if(start == end) //考虑起点终点相同的情况
continue;
capacity[start][end] +=ci; //此处注意可能出现多条同一起点终点的情况
}
cout<<maxFlow(1,m)<<endl;
}
return 0;
}
显而易见capacity存变的流量,进行ek求解。
对于BFS找增广路:
- 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寻找路径
路径也自然变成了这样:

- 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(这个就是最大流的值)
二、算法分析
- 时间复杂度为O(m2n)
- 而接下来的Dinic算法的时间复杂度为O(n2m)
最大流——EK算法的更多相关文章
- 二分图的最大匹配——最大流EK算法
序: 既然是个图,并且求边数的最大值.那么这就可以转化为网络流的求最大流问题. 只需要将源点与其中一子集的所有节点相连,汇点与另一子集的所有节点相连,将所有弧的流量限制置为1,那么最大流 == 最大匹 ...
- 最大流EK算法/DINIC算法学习
之前一直觉得很难,没学过网络流,毕竟是基础知识现在重新来看. 定义一下网络流问题,就是在一幅有向图中,每条边有两个属性,一个是cap表示容量,一个是flow 表示流过的流量.我们要求解的问题就是从S点 ...
- (通俗易懂小白入门)网络流最大流——EK算法
网络流 网络流是模仿水流解决生活中类似问题的一种方法策略,来看这么一个问题,有一个自来水厂S,它要向目标T提供水量,从S出发有不确定数量和方向的水管,它可能直接到达T或者经过更多的节点的中转,目前确定 ...
- vector实现最大流EK算法
序: 在之前的文章中实现了不利用STL实现EK算法,效率也较高.这次我们企图简化代码,减少变量的使用与手写模拟的代码. 注意:vector等STL的container在不开O2优化的时候实现同一个效果 ...
- 最大流EK算法模板
最近学了下最大流算法,大概思想算是懵懵懂懂了,现在想把模板记录下来,以备后面深刻学习之用. #include<cstdio> #include<cstring> using n ...
- POJ-1459(最大流+EK算法)
Power Network POJ-1459 这题值得思索的就是特殊的输入,如何输入一连串字符.这里采用的方法是根据输入已知的输入格式,事先预定好要接受的数据类型. 这里套用的板子也是最大流的模板,但 ...
- 【转】最大流EK算法
转自:http://www.cnblogs.com/kuangbin/archive/2011/07/26/2117636.html 图-1 如图-1所示,在这个运输网络中,源点S和汇点T分别是1,7 ...
- POJ1273 最大流 EK算法
套了个EK的模板 //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #include <stdi ...
- 最大流EK算法
给定一个有向图G=(V,E),把图中的边看作 管道,每条边上有一个权值,表示该管道 的流量上限.给定源点s和汇点t,现在假设 在s处有一个水源,t处有一个蓄水池,问从 s到t的最大水流量是多少? 网络 ...
随机推荐
- mysql慢查询开启及分析方法
最近服务维护的公司的DB服务器,总是会出现问题,感觉需要优化一下了,登陆上去,发现慢查询日志都没有开,真是惭愧, 故果断加上慢查询日志, 经过分析sql记录,发现问题很多,开发人员很多没有对sql优化 ...
- JavaScript js调用堆栈(一)
本文主要介绍JavaScript程序内部的执行机制 首先先了解什么是执行上下文 执行上下文就是当前JavaScript代码被解析和执行是所在环境的抽象概念,JavaScript中运行任何的代码都是在执 ...
- vue2.0+node.js+mongodb全栈打造商城
Github地址:https://github.com/ccyinghua/vue-node-mongodb-project 一.构建项目所用: vue init webpack vue-node-m ...
- 面试遇到的select into 但是在PL/SQL developer ORA-00905:缺失关键字"错误。
select into 是什么意思. 1.INSERT INTO SELECT语句 语句形式为:Insert into Table2(field1,field2,...) select value1, ...
- Swift_数组详解
Swift_数组详解 点击查看源码 初始化 //初始化 fileprivate func testInit() { //空数组 var array = [Int]() print(array) arr ...
- 简明 ES6 模块
简明 ES6 模块 1.什么是模块 模块就是一段代码,这段代码可以反复使用,经常单独写成一个文件,一旦加载会立即执行. 2.导出 导出有 2 种方式:命名导出和默认导出,分别用关键字export和ex ...
- Java程序如何生成Jar 执行文件(2)
一.用Eclipse生产Jar文件 注意:此方法可以打包含有第三方jar包的项目 1. 首先,右键你的Java工程,选择Export,在Java文件夹下选择Runnable JAR file,如下图所 ...
- 【模板】素数测试(Miller-Rabin测试)
基础素数测试模板 对于大数的素性判断,目前Miller-Rabin算法应用最广泛.一般底数仍然是随机选取,但当待测数不太大时,选择测试底数就有一些技巧了.比如,如果 被测数小于4759123141,那 ...
- MySql Connector/C++8事务处理Demo
#include <iostream> #include <exception> #include <vector> #include <unistd.h&g ...
- MySQL备份恢复之mysqldump
Preface The day before yesterday,there's a motif about the lock procedure when backing up My ...