先推荐一个讲网络流的博客,我的网络流知识均吸收于此   传送门

EdmondsKarp算法基本思想:从起点到终点进行bfs,只要存在路,说明存在增广路径,则取这部分路 权值最小的一部分,即为增广路径(也就是这一部分路的最大流量)。然后将这条路上的正向权值都减去min,反向权值都加上min(即,m[i][j]-min,m[j][i]+min,为什么等会再解释)。然后重复此操作,最终就得到了最大流。

先上模板(也是取自于刚才的博客,真的写的很精简很好懂)。

邻接矩阵版本。

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MAXN = ;
const int MAX_INT = (( << ) - ); int n; // 图中点的数目
int pre[MAXN]; // 从 s - t 中的一个可行流中, 节点 i 的前序节点为 Pre[i];
bool vis[MAXN]; // 标记一个点是否被访问过
int mp[MAXN][MAXN]; // 记录图信息 bool bfs(int s, int t){
queue <int> que;
memset(vis, , sizeof(vis));
memset(pre, -, sizeof(pre));
pre[s] = s;
vis[s] = true;
que.push(s);
while(!que.empty()){
int u = que.front();
que.pop();
for(int i = ; i <= n; i++){
if(mp[u][i] && !vis[i]){
pre[i] = u;
vis[i] = true;
if(i == t) return true;
que.push(i);
}
}
}
return false;
} int EK(int s, int t){
int ans = ;
while(bfs(s, t)){
int mi = MAX_INT;
for(int i = t; i != s; i = pre[i]){
mi = min(mi, mp[pre[i]][i]);
}
for(int i = t; i != s; i = pre[i]){
mp[pre[i]][i] -= mi;
mp[i][pre[i]] += mi;
}
ans += mi;
}
return ans;
}
 

这部分代码唯一不好理解的就是,思考了很久,终于在跑步时想通了这部分代码的原理。

for(int i = t; i != s; i = pre[i]){
mp[pre[i]][i] -= mi;
mp[i][pre[i]] += mi;
}

mp[pre[i]][i]-mi好理解,因为已经流过了嘛,那为什么有mp[i][pre[i]]+=mi呢?让我们看一个具体的例子。

按照我们的做法,第一次得到了1-2-4-6这条路径,会发现最大流此时是2,然后将路径上的值全部减去2,然后得到的图是这样的:

如果只减掉了正向的路径的权值,这个图就不连通了,也就是答案是2,然而其实答案是3,为什么呢,让我们加上反向的权值看一下:

红色的就是反向的权值,然后再进行上述过程,会发现还有一条 1-3-4-2-5-6的路径,权值为1,所以答案是2+1=3.(这个答案大家可以根据第一幅图自己想一下,会发现就是3,好神奇有木有?)

那为什么这么神奇呢,我的理解是,反向路径代表了,这条路曾经通了多少水,比如2-4这条就通2滴水,然后在第二条路径中通过的这1滴水,其实就是2号路径跟1号路径说,你原本在2-4这条路上有两滴水,现在分一滴到我想去的地方,然后我的水去你想去的地方,这样我们都能实现目标。(想一下是不是这么回事)。

解决了这个难题,那EK算法的模板你就理解啦!

接下来送上邻接表的版本。

const int MAXN = ;
const int MAX_INT = ( << ); struct Edge{
int v, nxt, w;
}; struct Node{
int v, id;
}; int n, m, ecnt;
bool vis[MAXN];
int head[MAXN];
Node pre[MAXN];
Edge edge[MAXN]; void init(){
ecnt = ;
memset(edge, , sizeof(edge));
memset(head, -, sizeof(head));
} void addEdge(int u, int v, int w){
edge[ecnt].v = v;
edge[ecnt].w = w;
edge[ecnt].nxt = head[u];
head[u] = ecnt++;
} bool bfs(int s, int t){
queue <int> que;
memset(vis, , sizeof(vis));
memset(pre, -, sizeof(pre));
pre[s].v = s;
vis[s] = true;
que.push(s);
while(!que.empty()){
int u = que.front();
que.pop();
for(int i = head[u]; i + ; i = edge[i].nxt){
int v = edge[i].v;
if(!vis[v] && edge[i].w){
pre[v].v = u;
pre[v].id = i;
vis[v] = true;
if(v == t) return true;
que.push(v);
}
}
}
return false;
} int EK(int s, int t){
int ans = ;
while(bfs(s, t)){
int mi = MAX_INT;
for(int i = t; i != s; i = pre[i].v){
mi = min(mi, edge[pre[i].id].w);
}
for(int i = t; i != s; i = pre[i].v){
edge[pre[i].id].w -= mi;
edge[pre[i].id ^ ].w += mi;
}
ans += mi;
}
return ans;
} // 加边
addEdge(u, v, w);
addEdge(v, u, );
// 调用
int ans = EK(s, t);

网络流EdmondsKarp算法模板理解的更多相关文章

  1. POJ 1273 Drainage Ditches(网络流dinic算法模板)

    POJ 1273给出M条边,N个点,求源点1到汇点N的最大流量. 本文主要就是附上dinic的模板,供以后参考. #include <iostream> #include <stdi ...

  2. 网络流Edmonds-Karp算法入门

    今天自习课没事干,看书自学了一下网络流中的EK算法.(求最大流) 设s为源点,t为汇点,C为容量矩阵,F为流量矩阵,f为最大流量. 1.初始化F,f 2.用BFS在残量网络中找到一条从s到t的最短增广 ...

  3. 网络流EK算法模板

    \(EK\)算法的思想就是每一次找一条增广路进行增广. 注意几个点: 存图时\(head\)数组要设为\(-1\). 存图的代码是这样的: inline void add(int u, int v, ...

  4. POJ 3281 [网络流dinic算法模板]

    题意: 农场主有f种食物,d种饮料,n头牛. 接下来的n行每行第一个数代表第i头牛喜欢吃的食物数量,和第i头牛喜欢喝的饮料数目. 接下来分别是喜欢的食物和饮料的编号. 求解:农场主最多能保证几头牛同时 ...

  5. 网络流 EK算法模板。

    这篇博客讲得很好 #include<queue> #include<stdio.h> #include<string.h> using namespace std; ...

  6. 网络流Dinic算法模板 POJ1273

    这就是以后我的板子啦~~~ #include <queue> #include <cstdio> #include <cstring> #include <a ...

  7. HDU1532最大流 Edmonds-Karp,Dinic算法 模板

    Drainage Ditches Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) To ...

  8. ACM - 图论- 网络流 - 算法模板

    \(EK\) 算法模板 #include <iostream> #include <queue> #include<string.h> using namespac ...

  9. POJ 1273 - Drainage Ditches - [最大流模板题] - [EK算法模板][Dinic算法模板 - 邻接表型]

    题目链接:http://poj.org/problem?id=1273 Time Limit: 1000MS Memory Limit: 10000K Description Every time i ...

随机推荐

  1. MSSQL 数据库日志爆涨

    解决方法有两种,现只用最简单的方法: 1.数据库属性----选项----恢复模式由完整改为简单--确定 2.右击数据库---任务---收缩 3.数据库属性----选项----恢复模式由简单改为完整-- ...

  2. js 操作属性,操作内容,

    disable=“disable” 让按钮变得不可选 先建一个按钮,让class = ’btn‘ 然后, 添加,修改属性 document.getElementsByClassName('btn')[ ...

  3. [转]JQuery 如何选择带有多个class的元素

    比如下面代码需要选择同时带有这几个class的元素,怎么写? 1 <div class="modal fade in"></div> A: 1. 依次过滤 ...

  4. 服务机器人的小脑——SLAM技术

    博客转载自:https://www.leiphone.com/news/201706/DZlMscTwdIzFyodg.html 雷锋网(公众号:雷锋网)按:本文作者SLAMTEC(思岚科技公号sla ...

  5. java内存模型和线程安全

  6. c++正确处理 is-a has-a关系

    比如.我们想实现一个Set类,而已经有一个List类可提供给你使用,我们到底用is-a(public继承)关系还是用has-a(组合)关系呢? 1:如果使用is-a关系,则 class Set:pub ...

  7. DBUtils工具类和DBCP连接池

    今日内容介绍 1.DBUtils2.处理结果集的八种方式3.连接池4.连接池的用法1 PrepareStatement接口预编译SQL语句 1.1 预处理对象 * 使用PreparedStatemen ...

  8. c# 使用protobuf格式操作 Redis

    protobuf格式介绍 1.protobuf为goole定义的类似于json的数据格式.2.最终都需要序列化为二进制形式进行传输存储.3.相对于xml,json格式来说,序列化为二进制后占用空间更小 ...

  9. IDEA内嵌Jetty启动SpringMvc项目

    这段时间本意是想要研究一下Netty的多线程异步NIO通讯框架,看完原理想要做下源码分析.查找资料发现Jetty框架底层支持用Netty做web请求的多线程分发处理,于是就筹备着将Jetty框架内嵌到 ...

  10. Windows7 安装TensorFlow(本人试了好多方法后的成果)

    本人机器为64位win7 首先安装python,版本一定要注意,TennsorFlow要使用 Python3.0 系列版本不能使用2.0系列版本,但是TensorFlow 的安装包目前windows版 ...