感谢董晓老师:博客b站

/*
Dinic算法的思路是,用bfs进行分层,限制后面dfs每次的搜索深度,
并且,在dfs的过程中,直接把当前这个路走到u的容量限制分给u的各个出边
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int N = 10020, M = 200020;
typedef long long LL;
struct Edge
{
LL v, c, ne;
} e[M]; int n, m, S, T; int h[N], idx = 1; // 由于有反向边,所以边要两两配对,这里放弃01这一对,从2,3开始配对 int d[N]; // d数组存储的是每个点在这一轮的层次
int cur[N]; // cur[u]用于存储上次沿着某个路走到u这个点的容量是分配到那个出边被耗完的 void add(int a, int b, int c)
{
e[++idx] = {b, c, h[a]};
h[a] = idx;
}
bool bfs()
{
memset(d, 0, sizeof d); // 每次bfs要重新分层,所以每次一开始要做的是层次初始化为0,同时也可以用d数组判定是否遍历过
//! 这里因为写成sizeof 0错了
queue<int> q; q.push(S);
d[S] = 1; // 层次从1开始 while (q.size())
{
auto u = q.front();
q.pop(); for (int i = h[u]; i; i = e[i].ne)
{
auto v = e[i].v; if (d[v] == 0 && e[i].c) // 如果这一次bfs还没有遍历到v,并且uv这条路剩余容量上限不为0
{
d[v] = d[u] + 1;
q.push(v);
if (v == T)
return true; // 只要找到了T就行,找到了T说明T是最深的一层,那么就是说,其他的点都找过了,因此可以直接退出来
}
}
}
return false;
} LL dfs(int u, LL mf) // 深搜,不断把当前这条都到u的路的容量上限mf分配给u的各个出边
// 并且返回一共分了多少出去
{
if (u == T)
{
return mf; // 如果这个点是汇点,那么就不用往后分了,或者说可以认为是T后面可以分无限多,所以分出去的就是mf
} LL sum = 0; // 用于记录分了多少出去 for (int i = cur[u]; i; i = e[i].ne) // cur[u]一开始存储的是h[u]也就是u的第一个出边的编号,这里cur用于存储上一次dfs到u是在到个边把容量量上限耗完的,之所以前面的边不用管,是因为一定把那些边都填到上限了才会到这个边
{
cur[u] = i; //! 更新当前弧,这也叫当前弧优化 auto v = e[i].v;
if (d[v] == d[u] + 1 && e[i].c) // 为了限制深搜的深度,要根据bfs分的层来遍历,并且要求这个边剩余的容量上限不为0
{ //! 这里曾经因为等于写成赋值错了
LL f = dfs(v, min(mf, e[i].c)); // 走到v的容量上限是之前走到u的容量上限mf和(u,v)这条边的上限取min,这里是要递归的去求让v把能留到t的容量上限尽可能多的分出去
e[i].c -= f; // (u,v)这条边的容量会减去从v分走的流量
e[i ^ 1].c += f; // 反向边
sum += f; // 从u出去的总流量要加上从v出去的总流量
mf -= f; // 走到u的容量上限被v拿去消耗了
if (mf == 0)
break; // 如果mf已经被消耗完了,说明这次走到u的容量限制已经没有了,直接退出循环,不用再找u的其他子节点了
//! 余量优化
}
}
if (sum == 0)
{
d[u] = 0; // 如果sum=0,说明从u这个点已经无法把流量分出去了,所以u这个点的层次设为0,以后不用再遍历u了
} //! 残枝优化 return sum; // 返回当前这个点可以分出去多少流量
} LL dinic()
{
LL flow = 0; while (bfs()) // bfs用于给点分层,返回是否能遍历到T,如果不能就说明图已经没有可以走得增广路了,找不到可行流了
{
memcpy(cur, h, sizeof h); // 将cur初始为每个点的第一个出边
flow += dfs(S, 1e9); // 一开始从S开始,容量上限设为无穷大
}
return flow;
} int main()
{
cin >> n >> m >> S >> T;
int a, b, c;
while (m--)
{ cin >> a >> b >> c; add(a, b, c);
add(b, a, 0); // 返现边容量上限初始为0
} cout << dinic() << endl; return 0;
}

网络流最大流Dinic算法的更多相关文章

  1. 网络流最大流——dinic算法

    前言 网络流问题是一个很深奥的问题,对应也有许多很优秀的算法.但是本文只会讲述dinic算法 最近写了好多网络流的题目,想想看还是写一篇来总结一下网络流和dinic算法以免以后自己忘了... 网络流问 ...

  2. [讲解]网络流最大流dinic算法

    网络流最大流算法dinic ps:本文章不适合萌新,我写这个主要是为了复习一些细节,概念介绍比较模糊,建议多刷题去理解 例题:codevs草地排水,方格取数 [抒情一下] 虽然老师说这个多半不考,但是 ...

  3. Power Network(网络流最大流 & dinic算法 + 优化)

    Power Network Time Limit: 2000MS   Memory Limit: 32768K Total Submissions: 24019   Accepted: 12540 D ...

  4. 网络流——最大流Dinic算法

    前言 突然发现到了新的一年什么东西好像就都不会了凉凉 算法步骤 建残量网络图 在残量网络图上跑增广路 重复1直到没有增广路(注意一个残量网络图要尽量把价值都用完,不然会浪费建图的时间) 代码实现 #i ...

  5. 网络流之最大流Dinic算法模版

    /* 网络流之最大流Dinic算法模版 */ #include <cstring> #include <cstdio> #include <queue> using ...

  6. 网络流(最大流-Dinic算法)

    摘自https://www.cnblogs.com/SYCstudio/p/7260613.html 网络流定义 在图论中,网络流(Network flow)是指在一个每条边都有容量(Capacity ...

  7. 学习笔记 --- 最大流Dinic算法

    为与机房各位神犇同步,学习下网络流,百度一下发现竟然那么多做法,最后在两种算法中抉择,分别是Dinic和ISAP算法,问过 CA爷后得知其实效率上无异,所以决定跟随Charge的步伐学习Dinic,所 ...

  8. hdu-3572 Task Schedule---最大流判断满流+dinic算法

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3572 题目大意: 给N个任务,M台机器.每个任务有最早才能开始做的时间S,deadline E,和持 ...

  9. 最大流——Dinic算法

    前面花了很长时间弄明白了压入-重标记的各种方法,结果号称是O(V3)的算法测demo的时候居然TLE了一个点,看了题解发现所有人都是用Dinic算法写的,但它的复杂度O(V2E)明显高于前者,具体是怎 ...

  10. 求最大流dinic算法模板

    //最短增广路,Dinic算法 struct Edge { int from,to,cap,flow; };//弧度 void AddEdge(int from,int to,int cap) //增 ...

随机推荐

  1. Python 潮流周刊#95:像人类一样使用计算机(摘要)

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...

  2. MQTT消息传递过程中,序列化协议如何选择?文本序列化还是二进制序列化协议。

    字符串消息的序列化 在上一篇文章中,我们使用MQTTnet 框架,实现了一个MQTT服务器.MQTT发布者进程.MQTT订阅者进程.在消息传递过程中,我们将控制台的字符串直接传递.因为MQTT是应用层 ...

  3. 使用傅里叶级数和Python表示方波

    引言 在信号处理和数字通信中,方波是非常常见的一种波形.方波是一种周期性波形,信号在两个固定的幅度之间跳跃,通常是"高"与"低"的状态.你可能会问,如何通过数学 ...

  4. ShardingJdbc学习笔记

    Mysql主从复制遇到问题 安装mysql Install/Remove of the Service Denied!错误的解决办法

  5. 基于Zookeeper实现调度任务选主及心跳检测

    在微服务架构中使用ZooKeeper实现分布式任务调度选主,并确保Follower节点能实时监控Master状态并及时触发重新选举,可以通过以下方案实现: 一.核心设计原理 1. ZooKeeper特 ...

  6. 至美!看AXUI如何美化原始HTML标签(reset/normalize)

    前言:不只是重置,而是重塑 在前端开发中,我们每天都会接触大量的原生 HTML 标签,例如 <button>.<input>.<a>.<table>.& ...

  7. grafana最新任意文件读取

    一.Grafana简介 Grafana是一个跨平台的开源的度量分析和可视化工具,可以通过将采集的数据查询然后可视化的展示,并及时通知.它主要有以下六大特点: 1.展示方式:快速灵活的客户端图表,面板插 ...

  8. 基于Kubernetes可扩展的Selenium 并行自动化测试部署及搭建(1)——Win10环境下Docker部署

    前言: 最近逛swtestacademy时候发现一篇基于kubernetes搭建selenium并行自动化测试的帖子,主要描述的是通过k8s动态扩展selenium grid来实现自动化测试用例在不同 ...

  9. SQL 日常练习 (十九)

    趁热打铁, 一波 SQL 继续带走 ~~ 虽然是假期, 但我也不想出去逛, 宅着也不想看书和思考人生, 除了做饭, 就更多对着电脑发呆. 时而看了下微信群, 初中小伙伴结合, 祝福寄语 和 随份子 都 ...

  10. LangChain4j如何自定义文档转换器实现数据清洗?

    LangChain4j 提供了 3 种 RAG(Retrieval-Augmented Generation,检索增强生成)实现,我们通常在原生或高级的 RAG 实现中,要对数据进行清洗,也就是将外接 ...