当前位置: 首页 > news >正文

【图论】网络流

网络流目前只整理模板,学习的话这篇博客可能不太适合

代码参考下方博客,加了一些自己的注释

  • 算法学习笔记(28): 网络流
  • 究级的最大流算法:ISAP与HLPP

FF 和 EK 仅用作理解代码,赛时请使用 Dinic 或 ISAP

下文建图方式都基于链式前向星,请注意,cnt 必须从 1 开始!!!!

void add(int u, int v, int val)
{cnt ++ ;node[cnt].to = v;node[cnt].w = val;node[cnt].next = head[u];head[u] = cnt;
}

文章目录

  • Ford-Fulkerson (FF算法)
  • Edmond-Karp (EK算法)
  • Dinic算法
  • Improved Shortest Augumenting Path (ISAP算法)

Ford-Fulkerson (FF算法)

基于dfs的最大流算法

时间复杂度 O ( e f ) O(ef) O(ef),e是边数,f是最大流

int n, m, start, end; // start是源点,end是汇点
bool st[MAXN]; // 标记某个点有没有被访问过struct edges
{int to, w, next;
};int dfs(int u, int flow) // u表示当前结点 flow表示目前流量
{if (p == t) return flow; // 到达终点,返回这条增广路的流量st[p] = true; // 标记已经访问过该点for (int eg = head[p]; eg != -1; eg = edges[eg].next) // 遍历所有邻接点{int to = edges[eg].to, w = edges[eg].w, c;if (w <= 0) continue; // 这条边不能再流过流量if (st[to]) continue; // 已经经过该点c = dfs(to, min(w, flow)); // 递归判断接下来能否到达终点 传递下去的流量是边的容量w与当前流量flow中的较小值if (c != -1) // 可以到达终点{edges[eg].w -= c; // 正向边容量w减去流量cedges[eg ^ 1].w += c; // 反向边容量w加上流量c// 建图时要把cnt置为1,且要保证反向边紧接着正向边建立return c; // 返回值是流量}}return -1; // 无法到达终点
}int FF()
{int ans = 0, c; // ans代表总流量while ((c = dfs(start, INF)) != -1) // 只要还可以到达终点就一直dfs下去{memset(st, 0, sizeof(st)); // 初始化每个点的访问状态ans += c; // 加上本次dfs的流量}return ans;
}

Edmond-Karp (EK算法)

基于bfs的最大流算法

时间复杂度 O ( v e 2 ) O(ve^2) O(ve2),v是点数,e是边数

// last表示该条增广路中通向该点的边的编号 flow表示每个点可以流过的最大流量(也就是从上一个点传过来的流量)
int n, m, start, end, last[MAXN], flow[MAXN]; struct edges
{int to, w, next;
};int bfs()
{memset(last, -1, sizeof(last)); // 初始化每个点的增广路径queue<int> q;q.push(start);flow[start] = INF; // 源点可以流过的流量初始化为无穷大while (!q.empty()){int u = q.front();q.pop();if (u == t) break; // 到达汇点,结束搜索for (int eg = head[u]; eg != -1; eg = edges[eg].next) // 遍历所有邻接点{int to = edges[eg].to, w = edges[eg].w;if (w > 0 && last[to] == -1) // 如果残余容量大于0且未访问过(所以last保持在-1){last[to] = eg; // 记录点to在本条增广路的上一条边的编号是egflow[to] = min(flow[p], w); // 取边的容量和上一个点可以流过的流量的最小值q.push(to); // 新点入队}}}return last[end] != -1; // 如果汇点没有访问到,说明没有可以通向汇点的路了
}int EK()
{int maxflow = 0; // maxflow代表总流量while (bfs()) // 只要还可以到达终点就一直bfs下去{maxflow += flow[end]; // 更新总流量 也就是加上能流到汇点的流量for (int i = end; i != start; i = edges[last[i] ^ 1].to) // 从汇点原路返回更新残余容量{edges[last[i]].w -= flow[end]; // 正向边容量w减去该条增广路流量flow[end]edges[last[i] ^ 1].w += flow[end]; // 反向边容量w加上该条增广路流量flow[end]}}return maxflow;
}

Dinic算法

基于FF和EK的最大流算法

时间复杂度 O ( n 2 e ) O(n^2e) O(n2e),n是点数,e是边数

先使用bfs分层,再使用dfs搜索,每次只往层数高的地方走,可以避免走重复的路径

优化:

  • 多路增广:在某点找到一条增广路,如果流量没用完,就接着往下bfs
  • 当前弧优化:在Dinic中每条边只会增广一次,所以下次增广就不需要考虑已经增广过的边,通过修改起始结点可以实现这个优化

注意:Dinic用在二分图中复杂度是 O ( v e ) O(v\sqrt{e}) O(ve ),v是点数,e是边数 ,优于匈牙利算法。

int n, m, start, end, dep[MAXN], cur[MAXN]; // dep是每个点的层数 cur用于当前弧优化标记增广起点struct edges
{int to, w, next;
};bool bfs() // BFS分层
{memset(dep, -1, sizeof(dep)); // 初始化点的层数dep[start] = 0; // 初始化源点的层数为0memcpy(cur, head, sizeof(head)); // 当前弧优化初始化queue<int> q;q.push(start); // 源点入队while (!q.empty()){int u = q.front();q.pop();for (int eg = head[u]; eg; eg = edges[eg].next) // 遍历所有邻接点{int to = edges[eg].to, w = edges[eg].w;if (w > 0 && dep[to] == -1) // dep为-1说明没访问过{dep[to] = dep[u] + 1; // 更新to点层数q.push(to);}}}return dep[end] != -1; // 如果汇点未访问过说明已经无法达到汇点,此时返回false
}int dfs(int u, int flow) // u表示当前结点 flow表示目前流量
{if (u == end) return flow; // 找到汇点 返回目前的流量int rmn = flow; // rmn表示剩余的流量for (int eg = cur[u]; eg != -1; eg = edges[eg].next) // 遍历所有邻接点{if (rmm == 0) break; // 无余量直接退出cur[u] = eg; // 当前弧优化 更新当下次访问该点时从哪条边开始遍历int to = edges[eg].to, w = edges[eg].w;if (w > 0 && dep[to] == dep[u] + 1) // 往层数高的方向增广{int c = dfs(to, min(w, rmn)); // 递归得到该点流量 传递下去的流量是边的容量w与当前流量flow中的较小值rmn -= c; // 剩余流量减少edges[eg].w -= c; // 正向边容量w减去流量cedges[eg ^ 1].w += c; // 反向边容量w加上流量c}}return flow - rmn; // 返回传递的流量的大小
}int dinic()
{int ans = 0; // ans代表总流量while (bfs()) // 只要还可以到达终点就一直bfs下去ans += dfs(start, INF);return ans;
}

Improved Shortest Augumenting Path (ISAP算法)

考虑到Dinic中可能需要bfs多次,ISAP对此做出改进,只需要进行一次bfs即可

首先跑一遍bfs,从汇点到源点处理每个结点的深度

再从源点到汇点跑dfs,和Dinic类似,只是当一个点跑完后,如果从上一个点传过来的流量 flow 比该点的流过的流量 used 大,说明这个点的使用价值已经榨干了,但是还有剩余的流量,则把它的深度加1,如果出现断层(某个深度没有点),结束算法,没出现就一直跑下去

下方代码已加入当前弧优化

struct Edge
{int to, next, w;
};int dep[maxn], gap[maxn]; // dep[i]表示结点i在第几层 gap[i]表示第i层有多少结点
void bfs()
{memset(dep, -1, sizeof(dep));memset(gap, 0, sizeof(gap));dep[end] = 0; // 汇点层数初始化为0gap[0] = 1; // 层数为0的点个数初始化为1queue<int> q;q.push(end); // 汇点入队while (!q.empty()){int u = q.front();q.pop();for (int i = head[u]; i != -1; i = edge[i].next){int to = edge[i].to;if (dep[to] != -1) continue; // 层数不为-1说明已经访问过这个点了dep[to] = dep[u] + 1; // 更新to点层数gap[dep[to]] ++ ; // 更新该层数点的数量 q.push(to); // to点入队}}return;
}int maxflow;
int dfs(int u, int flow) // u表示当前结点 flow表示目前流量
{if (u == end) // 找到汇点{maxflow += flow; // 更新最大流量return flow; // 返回目前的流量}int used = 0; // 从u开始使用的流量for (int i = cur[u]; i != -1; i = edge[i].next){cur[u] = i; // 当前弧优化 更新当下次访问该点时从哪条边开始遍历int to = edge[i].to, w = edge[i].w;if (w > 0 && dep[to] + 1 == dep[u]) // 边还有余量and层数符合要求(注意计算层数的时候是从汇点到源点的){int c = dfs(to, min(w, flow - used)); // 递归得到该点流量 传递下去的流量是边的容量w与当前流量flow-used中的较小值if (c > 0){edge[i].w -= c; // 正向边容量w减去流量cedge[i ^ 1].w += c; // 反向边容量w加上流量cused += c; // 更新已经用过的流量}if (used == flow) return used; // used和flow相等说明已经没有剩余流量分给其他的边了 所以直接返回}}// 如果能到这一步 说明u的所有邻接点都已经遍历过了 且还有剩余流量// 此时我们需要修改u点的层数gap[dep[u]] -- ; // 修改原本层数的结点数if (gap[dep[u]] == 0) dep[start] = n + 1; // 说明没有层数为dep[u]的结点了 断层 不可能再到达汇点了dep[u] ++ ; // 更新u的层数gap[dep[u]] ++ ; // 更新新层数的结点数return used; // 返回流过的流量
}int ISAP()
{maxflow = 0; // maxflow是最大流量bfs();while (dep[start] < n){memcpy(cur, head, sizeof(head));dfs(s, INF);}return maxflow;
}

相关文章:

【图论】网络流

网络流目前只整理模板&#xff0c;学习的话这篇博客可能不太适合 代码参考下方博客&#xff0c;加了一些自己的注释 算法学习笔记(28): 网络流究级的最大流算法&#xff1a;ISAP与HLPP FF 和 EK 仅用作理解代码&#xff0c;赛时请使用 Dinic 或 ISAP 下文建图方式都基于链式…...

【Matplotlib】figure方法 你真的会了吗!?

&#x1f388;个人主页&#xff1a;甜美的江 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;matplotlib &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进…...

[C++]继承(续)

一、基类和派生类对象赋值转换 在public继承时&#xff0c;父类和子类是一个“is - a”的关系。 子类对象赋值给父类对象/父类指针/父类引用&#xff0c;我们认为是天然的&#xff0c;中间不产生临时对象&#xff0c;也叫作父子类赋值兼容规则&#xff08;切割/切片&#xff…...

恒创科技:服务器内存不足影响大吗?

​  服务器在为网站、应用程序和在线服务提供支持方面发挥着关键作用。这些服务器需要提供最佳性能&#xff0c;以确保正常无缝的用户体验&#xff0c;而RAM是显著影响服务器性能的关键配置之一。 RAM 是一种随机存取存储器&#xff0c;计算机和服务器使用它来临时存储正在使…...

深入理解网络通信和TCP/IP协议

目录 计算机网络是什么&#xff1f; 定义和分类 计算机网络发展简史 计算机网络体系结构 OSI 七层模型 TCP/IP 模型 TCP/IP 协议族 TCP/IP 网络传输中的数据 地址和端口号 MAC地址 IP 地址 端口号 为什么端口号有65535个&#xff1f; 综述 TCP 特性 TCP 三次握…...

Open CASCADE学习|分割曲线

1、通过参数进行分割 分别获得曲线的 FirstParameter 和 LastParameter &#xff0c;然后对参数进行分割&#xff0c;获得n个ui&#xff0c;并对每个ui调用D0&#xff08;获得这个点的坐标值&#xff09;或D1&#xff08;获得这个点的坐标值和切向量&#xff09;。这个方法的优…...

vulhub中Adminer远程文件读取漏洞复现(CVE-2021-43008)

Adminer是一个PHP编写的开源数据库管理工具&#xff0c;支持MySQL、MariaDB、PostgreSQL、SQLite、MS SQL、Oracle、Elasticsearch、MongoDB等数据库。 在其版本1.12.0到4.6.2之间存在一处因为MySQL LOAD DATA LOCAL导致的文件读取漏洞。 参考链接&#xff1a; https://gith…...

MOS管驱动电流估算-Qg参数

MOS管驱动电流估算 例&#xff1a;FDH45N50F如下参数&#xff1a; 有人可能会这样计算&#xff1a; 开通电流 带入数据得 关断电流 带入数据得 于是乎得出这样的结论&#xff0c;驱动电流只需 250mA左右即可。仔细想想这样计算对吗&#xff1f; 这里必须要注意这样一个条件细…...

Vision Transfomer系列第一节---从0到1的源码实现

本专栏主要是深度学习/自动驾驶相关的源码实现,获取全套代码请参考 这里写目录标题 准备逐步源码实现数据集读取VIt模型搭建hand类别和位置编码类别编码位置编码 blocksheadVIT整体 Runner(参考mmlab)可视化 总结 准备 本博客完成Vision Transfomer(VIT)模型的搭建和flowers数…...

【CSS + ElementUI】更改 el-carousel 指示器样式且隐藏左右箭头

需求 前三条数据以走马灯形式展现&#xff0c;指示器 hover 时可以切换到对应内容 实现 <template><div v-loading"latestLoading"><div class"upload-first" v-show"latestThreeList.length > 0"><el-carousel ind…...

Ubuntu 22.04 上安装和使用 Go

1.下载  All releases - The Go Programming Language //https://golang.google.cn/dl/wget https://golang.google.cn/dl/go1.21.6.linux-amd64.tar.gz 2.在下载目录下执行&#xff0c;现在&#xff0c;使用以下命令将文件提取到 “/usr/local ” 位置 sudo tar -C /usr/…...

ES6-const

一、基本用法 - 语法&#xff1a;const 标识符初始值;注意:const一旦声明变量&#xff0c;就必须立即初始化&#xff0c;不能留到以后赋值 - 规则&#xff1a;1.const 声明一个只读的常量&#xff0c;一旦声明&#xff0c;常量的值就不能改变2.const 其实保证的不是变量的值不…...

Android消息通知Notification

Notification 发送消息接收消息 #前言 最近在做消息通知类Notification的相关业务&#xff0c;利用闲暇时间总结一下。主要分为两部分来记录&#xff1a;发送消息和接收消息。 发送消息 发送消息利用NotificationManager类的notify方法来实现&#xff0c;现用最普通的方式发…...

2V2无人机红蓝对抗仿真

两架红方和蓝方无人机分别从不同位置起飞&#xff0c;蓝方无人机跟踪及击毁红方无人机 2020a可正常运行 2V2无人机红蓝对抗仿真资源-CSDN文库...

VUE3语法--computed计算属性中get和set使用案例

1、功能概述 计算属性computed是Vue3中一个响应式的属性,最大的用处是基于多依赖时的监听。也就是属性A的值可以根据其他数据的变化而响应式的变化。 在Vue3中,你可以使用computed函数来定义计算属性。computed函数接收两个参数:一个包含getter和setter函数的对象和可选的…...

Linux cd 和 df 命令执行异常

这篇记录一些奇奇怪怪的命令执行异常的情况&#xff0c;后续有新的发现也会补录进来 情况一 /tmp 目录权限导致 按 tab 补充报错 情况描述 cd 按 tab 自动补充文件报错&#xff08;普通用户&#xff09; bash: cannot create temp file for here-document: Permission denie…...

【计算机网络】物理层概述|通信基础|奈氏准则|香农定理|信道复用技术

目录 一、思维导图 二、 物理层概述 1.物理层概述 2.四大特性&#xff08;巧记"械气功程") 三、通信基础 1.数据通信基础 2.趁热打铁☞习题训练 3.信号の变身&#xff1a;编码与调制 4.极限数据传输率 5.趁热打铁☞习题训练 6.信道复用技术 推荐 前些天发…...

XXE基础知识整理(附加xml基础整理)

全称&#xff1a;XML External Entity 外部实体注入攻击 原理 利用xml进行读取数据时过滤不严导致嵌入了恶意的xml代码&#xff1b;和xss原理雷同 危害 外界攻击者可读取商户服务器上的任意文件&#xff1b; 执行系统命令&#xff1b; 探测内网端口&#xff1b; 攻击内网网站…...

【pytorch】anaconda使用及安装pytorch

https://zhuanlan.zhihu.com/p/348120084 https://blog.csdn.net/weixin_44110563/article/details/123324304 介绍 Conda创建环境相当于创建一个虚拟的空间将这些包都装在这个位置&#xff0c;不需要了可以直接打包放入垃圾箱&#xff0c;同时也可以针对不同程序的运行环境选…...

SpringBoot过滤器获取响应的参数

一、背景 在项目开发过程中&#xff0c;需要对于某些接口统一处理。 这时候就需要获取响应的报文&#xff0c;再对获取的报文进行统一处理。 二、了解过滤器 首先了解一下过滤器拦截器的区别&#xff1a; JAVA中的拦截器、过滤器&#xff1a;https://blog.csdn.net/qq_38254…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

GraphQL 实战篇:Apollo Client 配置与缓存

GraphQL 实战篇&#xff1a;Apollo Client 配置与缓存 上一篇&#xff1a;GraphQL 入门篇&#xff1a;基础查询语法 依旧和上一篇的笔记一样&#xff0c;主实操&#xff0c;没啥过多的细节讲解&#xff0c;代码具体在&#xff1a; https://github.com/GoldenaArcher/graphql…...

自然语言处理——文本分类

文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益&#xff08;IG&#xff09; 分类器设计贝叶斯理论&#xff1a;线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别&#xff0c; 有单标签多类别文本分类和多…...

02.运算符

目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&&#xff1a;逻辑与 ||&#xff1a;逻辑或 &#xff01;&#xff1a;逻辑非 短路求值 位运算符 按位与&&#xff1a; 按位或 | 按位取反~ …...

门静脉高压——表现

一、门静脉高压表现 00:01 1. 门静脉构成 00:13 组成结构&#xff1a;由肠系膜上静脉和脾静脉汇合构成&#xff0c;是肝脏血液供应的主要来源。淤血后果&#xff1a;门静脉淤血会同时导致脾静脉和肠系膜上静脉淤血&#xff0c;引发后续系列症状。 2. 脾大和脾功能亢进 00:46 …...

PydanticAI快速入门示例

参考链接&#xff1a;https://ai.pydantic.dev/#why-use-pydanticai 示例代码 from pydantic_ai import Agent from pydantic_ai.models.openai import OpenAIModel from pydantic_ai.providers.openai import OpenAIProvider# 配置使用阿里云通义千问模型 model OpenAIMode…...

如何把工业通信协议转换成http websocket

1.现状 工业通信协议多数工作在边缘设备上&#xff0c;比如&#xff1a;PLC、IOT盒子等。上层业务系统需要根据不同的工业协议做对应开发&#xff0c;当设备上用的是modbus从站时&#xff0c;采集设备数据需要开发modbus主站&#xff1b;当设备上用的是西门子PN协议时&#xf…...

OPENCV图形计算面积、弧长API讲解(1)

一.OPENCV图形面积、弧长计算的API介绍 之前我们已经把图形轮廓的检测、画框等功能讲解了一遍。那今天我们主要结合轮廓检测的API去计算图形的面积&#xff0c;这些面积可以是矩形、圆形等等。图形面积计算和弧长计算常用于车辆识别、桥梁识别等重要功能&#xff0c;常用的API…...

更新 Docker 容器中的某一个文件

&#x1f504; 如何更新 Docker 容器中的某一个文件 以下是几种在 Docker 中更新单个文件的常用方法&#xff0c;适用于不同场景。 ✅ 方法一&#xff1a;使用 docker cp 拷贝文件到容器中&#xff08;最简单&#xff09; &#x1f9f0; 命令格式&#xff1a; docker cp <…...