EK算法(O(V*E^2))

网上很多都讲得挺好的,我是看这一篇的。他的代码简洁(超漂亮的!),但是优化不够,而且用了map存图。对于这道luogu的模板,不仅MLE还会TLE,但也不是没有参考性。https://www.cnblogs.com/ZJUT-jiangnan/p/3632525.html

需要改动的地方:

  1. 链式前向星存图
  2. 记录增广路上结点的前驱以及结点与其前驱之前的边的残余容量【这个是为了方便每次找增广路中边的最小残余容量
  3. bfs只用来判断源点到汇点是不是还有增广路,不要把残余容量最小值的更新放在bfs里面,会T一个点……找到增广路之后才来找增广路上的最小残余容量,然后才来更新残余网络~

EK算法的核心:

反复寻找源点s到汇点t之间的增广路径,若有,找出增广路径上每一段[容量-流量](残余容量)的最小值,若无,则结束。

  • 贴上参考学习笔记。他写的好全……暂时还没看完,日后接着看:https://www.luogu.com.cn/blog/user48036/solution-p3376
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3fusing namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 10004;
const int maxM = 100005;
inline int read()
{int x = 0, f = 1; char c = getchar();while(c < '0' || c > '9') { if(c == '-') f = -f; c = getchar(); }while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }return x * f;
}struct EDGE{int adj, to, w;EDGE(int a = -1, int b = 0, int c = 0): adj(a), to(b), w(c) {}
}edge[maxM << 1];
int head[maxN], cnt;void add_edge(int u, int v, int w)
{edge[cnt] = EDGE(head[u], v, w);head[u] = cnt ++;
}struct Pre{int last, Eid;
}pre[maxN];bool visited[maxN];void update_residual_network(int u, int flow)
{while(pre[u].last != -1){edge[pre[u].Eid].w -= flow;edge[pre[u].Eid ^ 1].w += flow;u = pre[u].last;}
}bool find_path_bfs(int s, int t) //源点 汇点
{memset(visited, false, sizeof(visited));memset(pre, -1, sizeof(pre));queue<int>q;q.push(s); visited[s] = true;while(!q.empty()){int u = q.front(); q.pop();for(int i = head[u]; ~i; i = edge[i].adj ){int v = edge[i].to;if(!visited[v] && edge[i].w){pre[v] = Pre{u, i};if(v == t) return true;q.push(v); visited[v] = true;}}}return false;
}int EK_maxFlow(int s, int t)
{int max_flow = 0;while(find_path_bfs(s, t)){int new_flow = INF;for(int i = t; i != s; i = pre[i].last)new_flow = min(new_flow, edge[pre[i].Eid].w);update_residual_network(t, new_flow);max_flow += new_flow;}return max_flow;
}int n, m, s, t;int main()
{memset(head, -1, sizeof(head));cnt = 0;n = read(); m = read(); s = read(); t = read();for(int i = 0; i < m; ++ i ){int u, v, w;u = read(); v = read(); w = read();add_edge(u, v, w);add_edge(v, u, 0);}printf("%d\n", EK_maxFlow(s, t));return 0;
}

Dinic算法(O(V^2*E))

首先了解层次图

  • 层次图,就是把图中的结点按照结点到源点的深度分“层”,只保留不同层之间的边的图。

算法步骤:

  1. 对残余网络进行分层【bfs得到】【也用来判断是否还存在增广路!如果汇点t的深度为0(初始化为0的),说明汇点不可到达
  2. 对层次图进行深搜增广
  3. 重复上面两步直到不存在增广路
  • 相比EK算法,Dinic增加了层次图来优化。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;inline int read()
{int x = 0, f = 1; char c = getchar();while(c < '0' || c > '9') { if(c == '-') f = -f; c = getchar(); }while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }return x * f;
}const int maxN = 10004;
const int maxM = 100005;int n, m, s, t;struct EDGE{int adj, to, w;EDGE(int a = -1, int b = 0, int c = 0): adj(a), to(b), w(c) {}
}edge[maxM << 1];
int head[maxN], cnt;void add_edge(int u, int v, int w)
{edge[cnt] = EDGE(head[u], v, w);head[u] = cnt ++ ;
}int deep[maxN];bool bfs()
{memset(deep, 0, sizeof(deep));deep[s] = 1;queue<int>q;q.push(s);while(!q.empty()){int u = q.front(); q.pop();for(int i = head[u]; ~i; i = edge[i].adj){int v = edge[i].to;if(!deep[v] && edge[i].w){deep[v] = deep[u] + 1;q.push(v);}}}return deep[t];
}int dfs(int u, int flow)
{if(u == t)return flow;for(int i = head[u]; ~i; i = edge[i].adj){int v = edge[i].to;if(deep[u] + 1 == deep[v] && edge[i].w){if(int newFlow = dfs(v, min(flow, edge[i].w))){edge[i].w -= newFlow;edge[i ^ 1].w += newFlow;return newFlow;}}}return 0;
}int dinic_maxFlow()
{int maxFlow = 0;while(bfs()){if(int newFlow = dfs(s, INF))maxFlow += newFlow;}return maxFlow;
}int main()
{memset(head, -1, sizeof(head));n = read(); m = read(); s = read(); t = read();for(int i = 0; i < m; ++ i ){int u, v, w;u = read(); v = read(); w = read();add_edge(u, v, w);add_edge(v, u, 0);}printf("%d\n", dinic_maxFlow());return 0;
}

P3376 【模板】网络最大流【EK算法+Dinic算法解】相关推荐

  1. 最大流EK和Dinic算法

    最大流EK和Dinic算法 EK算法 最朴素的求最大流的算法. 做法:不停的寻找增广路,直到找不到为止 代码如下: @Frosero #include <cstdio> #include ...

  2. 最大流算法模板:EK和dinic算法

    最大流算法模板:EK和dinic算法 一.EK算法模板 #include<iostream> #include<queue> using namespace std; cons ...

  3. 【ybt金牌导航3-2-1】【luogu P3376】网络最大流【Dinic算法】

    网 络 最 大 流 网络最大流 网络最大流 题目链接:ybt金牌导航3-2-1 / luogu P3376 题目 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入 第一行包含四个正整数 ...

  4. 网络流-最大流(Ford-Fulkerson算法Dinic算法)

    文章目录 最大流 FF算法: 增广路: 反边: 代码: Dinic算法: Dinic + 当前弧优化 最大流 就如同水流,存在一张图,既有起点又有终点,从起点流向终点的最大流量就是最大流. 在上面的图 ...

  5. [Luogu] P3376 模板-网络流-最大流

    题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...

  6. 【洛谷P3376】网络最大流【网络流】

    分析 网络流算法本身是之前学过的,今天拿出来复习打个板子. 最原始的思路应该是搜索每一条路,每次进行增广的操作,知道不能增广为止.显然,这种思路复杂度比较高. 如何进行优化?就是dinic算法.上面那 ...

  7. 二分图最大匹配(匈牙利算法Dinic算法)

    二分图最大匹配: 给出一个二分图,左边有若干个节点,右边有若干个节点,左边的节点想到匹配右边的节点,每个左边的节点每个都有若干个可以选择的对象,每个左边节点只能选择一个右边节点,每个右边节点也只能被选 ...

  8. 【网络流】最大流问题(EK算法带模板,Dinic算法带模板及弧优化,ISAP算法带模板及弧优化)上下界网络流

    本blog重点是代码 网络流的相关概念 流网络(flow network) 流(flow) 网络的流 残留网络(residual network) 增广路径(augmenting path) Edmo ...

  9. 网络最大流的三种基础算法

    #include<iostream> #include<cstring> #include<queue> #include<cstdio> #inclu ...

  10. dinic算法 c 语言,网络流入门—用于最大流的Dinic算法

    "网络流博大精深"-sideman语 一个基本的网络流问题 最早知道网络流的内容便是最大流问题,最大流问题很好理解: 解释一定要通俗! 如右图所示,有一个管道系统,节点{1,2,3 ...

最新文章

  1. 【怎样写代码】对象克隆 -- 原型模式(一):问题案例
  2. Spring框架集成mybatis框架的配置(笔记)
  3. 【javascript权威指南】类型转换
  4. idea下一次Jar包依赖问题的解决过程
  5. outlook advanced find 快捷键不起作用
  6. C++自定义对象如何支持Range-based循环语法
  7. Mybatis逆向工程自动生成代码文件
  8. python3 函数注意要点
  9. 微信小程序保存图片拒绝授权后的操作
  10. linux less从后向前查看日志信息
  11. 百度云盘免下载百度云盘全速下载方法
  12. Protues 8.8 SP1 无需破解 可用直装版 指路
  13. 01 分布式系统架构的冰与火
  14. Excel转PDF,Excel行数过多导致PDF折行、换行显示
  15. 一元函数积分学的概念与性质
  16. php给图片添加水印图片,PHP实现给图片添加文字水印
  17. 干掉Google Base? 微软欲推Fremont服务 (转自donews.com)
  18. 使用fiddle进行苹果手机app抓包教程
  19. mysql 行转列查询优化_行转列及列转行查询
  20. 学习线程安全队列ConcurrentQueue

热门文章

  1. three.js自定义材质各向异性
  2. a+b / a-b / a*b / a/b c++问题题解
  3. 博客-需求说明答辩总结
  4. 三阶行列式简便算法_三阶行列式计算方法
  5. 数据应用系统的压力测试方案
  6. Min GW 安装教程(转载)
  7. python后缀名_python后缀名
  8. c# .net Paypal支付Webhooks回调验证
  9. cdn回源php_CDN回源、网站解析 是什么意思?
  10. VRRP(虚拟路由冗余技术)