网络流EdmondsKarp算法模板理解
先推荐一个讲网络流的博客,我的网络流知识均吸收于此 传送门
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算法模板理解的更多相关文章
- POJ 1273 Drainage Ditches(网络流dinic算法模板)
POJ 1273给出M条边,N个点,求源点1到汇点N的最大流量. 本文主要就是附上dinic的模板,供以后参考. #include <iostream> #include <stdi ...
- 网络流Edmonds-Karp算法入门
今天自习课没事干,看书自学了一下网络流中的EK算法.(求最大流) 设s为源点,t为汇点,C为容量矩阵,F为流量矩阵,f为最大流量. 1.初始化F,f 2.用BFS在残量网络中找到一条从s到t的最短增广 ...
- 网络流EK算法模板
\(EK\)算法的思想就是每一次找一条增广路进行增广. 注意几个点: 存图时\(head\)数组要设为\(-1\). 存图的代码是这样的: inline void add(int u, int v, ...
- POJ 3281 [网络流dinic算法模板]
题意: 农场主有f种食物,d种饮料,n头牛. 接下来的n行每行第一个数代表第i头牛喜欢吃的食物数量,和第i头牛喜欢喝的饮料数目. 接下来分别是喜欢的食物和饮料的编号. 求解:农场主最多能保证几头牛同时 ...
- 网络流 EK算法模板。
这篇博客讲得很好 #include<queue> #include<stdio.h> #include<string.h> using namespace std; ...
- 网络流Dinic算法模板 POJ1273
这就是以后我的板子啦~~~ #include <queue> #include <cstdio> #include <cstring> #include <a ...
- HDU1532最大流 Edmonds-Karp,Dinic算法 模板
Drainage Ditches Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) To ...
- ACM - 图论- 网络流 - 算法模板
\(EK\) 算法模板 #include <iostream> #include <queue> #include<string.h> using namespac ...
- POJ 1273 - Drainage Ditches - [最大流模板题] - [EK算法模板][Dinic算法模板 - 邻接表型]
题目链接:http://poj.org/problem?id=1273 Time Limit: 1000MS Memory Limit: 10000K Description Every time i ...
随机推荐
- MSSQL 数据库日志爆涨
解决方法有两种,现只用最简单的方法: 1.数据库属性----选项----恢复模式由完整改为简单--确定 2.右击数据库---任务---收缩 3.数据库属性----选项----恢复模式由简单改为完整-- ...
- js 操作属性,操作内容,
disable=“disable” 让按钮变得不可选 先建一个按钮,让class = ’btn‘ 然后, 添加,修改属性 document.getElementsByClassName('btn')[ ...
- [转]JQuery 如何选择带有多个class的元素
比如下面代码需要选择同时带有这几个class的元素,怎么写? 1 <div class="modal fade in"></div> A: 1. 依次过滤 ...
- 服务机器人的小脑——SLAM技术
博客转载自:https://www.leiphone.com/news/201706/DZlMscTwdIzFyodg.html 雷锋网(公众号:雷锋网)按:本文作者SLAMTEC(思岚科技公号sla ...
- java内存模型和线程安全
- c++正确处理 is-a has-a关系
比如.我们想实现一个Set类,而已经有一个List类可提供给你使用,我们到底用is-a(public继承)关系还是用has-a(组合)关系呢? 1:如果使用is-a关系,则 class Set:pub ...
- DBUtils工具类和DBCP连接池
今日内容介绍 1.DBUtils2.处理结果集的八种方式3.连接池4.连接池的用法1 PrepareStatement接口预编译SQL语句 1.1 预处理对象 * 使用PreparedStatemen ...
- c# 使用protobuf格式操作 Redis
protobuf格式介绍 1.protobuf为goole定义的类似于json的数据格式.2.最终都需要序列化为二进制形式进行传输存储.3.相对于xml,json格式来说,序列化为二进制后占用空间更小 ...
- IDEA内嵌Jetty启动SpringMvc项目
这段时间本意是想要研究一下Netty的多线程异步NIO通讯框架,看完原理想要做下源码分析.查找资料发现Jetty框架底层支持用Netty做web请求的多线程分发处理,于是就筹备着将Jetty框架内嵌到 ...
- Windows7 安装TensorFlow(本人试了好多方法后的成果)
本人机器为64位win7 首先安装python,版本一定要注意,TennsorFlow要使用 Python3.0 系列版本不能使用2.0系列版本,但是TensorFlow 的安装包目前windows版 ...