P3376 【模板】网络最大流【EK算法+Dinic算法解】
EK算法(O(V*E^2))
网上很多都讲得挺好的,我是看这一篇的。他的代码简洁(超漂亮的!),但是优化不够,而且用了map存图。对于这道luogu的模板,不仅MLE还会TLE,但也不是没有参考性。https://www.cnblogs.com/ZJUT-jiangnan/p/3632525.html
需要改动的地方:
- 链式前向星存图
- 记录增广路上结点的前驱以及结点与其前驱之前的边的残余容量【这个是为了方便每次找增广路中边的最小残余容量
- 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))
首先了解层次图
- 层次图,就是把图中的结点按照结点到源点的深度分“层”,只保留不同层之间的边的图。
算法步骤:
- 对残余网络进行分层【bfs得到】【也用来判断是否还存在增广路!如果汇点t的深度为0(初始化为0的),说明汇点不可到达
- 对层次图进行深搜增广
- 重复上面两步直到不存在增广路
- 相比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算法解】相关推荐
- 最大流EK和Dinic算法
最大流EK和Dinic算法 EK算法 最朴素的求最大流的算法. 做法:不停的寻找增广路,直到找不到为止 代码如下: @Frosero #include <cstdio> #include ...
- 最大流算法模板:EK和dinic算法
最大流算法模板:EK和dinic算法 一.EK算法模板 #include<iostream> #include<queue> using namespace std; cons ...
- 【ybt金牌导航3-2-1】【luogu P3376】网络最大流【Dinic算法】
网 络 最 大 流 网络最大流 网络最大流 题目链接:ybt金牌导航3-2-1 / luogu P3376 题目 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入 第一行包含四个正整数 ...
- 网络流-最大流(Ford-Fulkerson算法Dinic算法)
文章目录 最大流 FF算法: 增广路: 反边: 代码: Dinic算法: Dinic + 当前弧优化 最大流 就如同水流,存在一张图,既有起点又有终点,从起点流向终点的最大流量就是最大流. 在上面的图 ...
- [Luogu] P3376 模板-网络流-最大流
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...
- 【洛谷P3376】网络最大流【网络流】
分析 网络流算法本身是之前学过的,今天拿出来复习打个板子. 最原始的思路应该是搜索每一条路,每次进行增广的操作,知道不能增广为止.显然,这种思路复杂度比较高. 如何进行优化?就是dinic算法.上面那 ...
- 二分图最大匹配(匈牙利算法Dinic算法)
二分图最大匹配: 给出一个二分图,左边有若干个节点,右边有若干个节点,左边的节点想到匹配右边的节点,每个左边的节点每个都有若干个可以选择的对象,每个左边节点只能选择一个右边节点,每个右边节点也只能被选 ...
- 【网络流】最大流问题(EK算法带模板,Dinic算法带模板及弧优化,ISAP算法带模板及弧优化)上下界网络流
本blog重点是代码 网络流的相关概念 流网络(flow network) 流(flow) 网络的流 残留网络(residual network) 增广路径(augmenting path) Edmo ...
- 网络最大流的三种基础算法
#include<iostream> #include<cstring> #include<queue> #include<cstdio> #inclu ...
- dinic算法 c 语言,网络流入门—用于最大流的Dinic算法
"网络流博大精深"-sideman语 一个基本的网络流问题 最早知道网络流的内容便是最大流问题,最大流问题很好理解: 解释一定要通俗! 如右图所示,有一个管道系统,节点{1,2,3 ...
最新文章
- 【怎样写代码】对象克隆 -- 原型模式(一):问题案例
- Spring框架集成mybatis框架的配置(笔记)
- 【javascript权威指南】类型转换
- idea下一次Jar包依赖问题的解决过程
- outlook advanced find 快捷键不起作用
- C++自定义对象如何支持Range-based循环语法
- Mybatis逆向工程自动生成代码文件
- python3 函数注意要点
- 微信小程序保存图片拒绝授权后的操作
- linux less从后向前查看日志信息
- 百度云盘免下载百度云盘全速下载方法
- Protues 8.8 SP1 无需破解 可用直装版 指路
- 01 分布式系统架构的冰与火
- Excel转PDF,Excel行数过多导致PDF折行、换行显示
- 一元函数积分学的概念与性质
- php给图片添加水印图片,PHP实现给图片添加文字水印
- 干掉Google Base? 微软欲推Fremont服务 (转自donews.com)
- 使用fiddle进行苹果手机app抓包教程
- mysql 行转列查询优化_行转列及列转行查询
- 学习线程安全队列ConcurrentQueue