网络流学习笔记

网络流基础

基本概念

  • 源点(source) s s s,汇点 t t t

  • 容量:约等于边权。不存在的边流量可视为 0 0 0 ( u , v ) (u,v) (u,v) 的流量通常记为 c ( u , v ) c(u,v) c(u,v)(capacity)。

  • 流(flow):每条边上的流不能超过它的容量,注意这个限制是所有经过路径的边共享的。除了源点和汇点,其他所有点流入的流量都等于流出的流量。通常用 f f f 表示。

  • 割:把结点分成两部分 { S , T } \{S,T\} {S,T},且满足 s ∈ S , t ∈ T s\in S,t\in T sS,tT { S , T } \{S,T\} {S,T} 是图的一个 s s s- t t t 割, s s s- t t t { S , T } \{S,T\} {S,T} 的容量为 ∑ u ∈ S ∑ v ∈ T c ( u , v ) \sum\limits_{u\in S}\sum\limits_{v\in T}c(u,v) uSvTc(u,v)

  • 残留网络:有源点、汇点,且每条边都有残留容量的网络。

  • 增广路:从残留网络的源点到汇点的路径。对于增广路,给每一条边都加上等量流量,此过程称为增广。

常见问题

  • 最大流问题:给定每条边的流量,求得尽可能大的流量。
  • 最小割问题:给定每条边的流量,求一个容量尽可能大的 s s s- t t t { S , T } \{S,T\} {S,T}
  • 最小费用最大流问题:给定每条边的流量和权值(费用),求对于所有可能的最大流,费用最小的一个。
  • 上下界网络流问题:给定每条边的流量上界和下界,求一种可行的流使得满足限制。

最大流问题

以下代码均为 P3376 【模板】网络最大流 代码。

先介绍一种思想——Ford–Fulkerson 增广(FF 增广)。即不断在残留网络中找一条增广路,向汇点发送可能的最大流量,得到新的残留网络,不断寻找增广路,直到没有增广路为止。此时有最大流。

在 FF 增广的过程中,为了保证正确性,我们要引入反向边。对于每一条边 ( u , v ) (u,v) (u,v),建一条 c ( v , u ) = 0 c(v,u)=0 c(v,u)=0 的反向边。反向边其实相当于一种撤回操作,因此在增广的过程中,给正向边减去流量的同时要给反向边加上流量。

反向边的“抵消”操作使得在错误的增广路选择顺序下也可以得到正确答案。

FF 增广的时间复杂度为 O ( E f max ⁡ ) O(Ef_{\max}) O(Efmax)

EK 算法

通过 BFS 实现的 FF 增广过程。最坏时间复杂度为 O ( V E 2 ) O(VE^2) O(VE2),一般可以处理 1 0 4 10^4 104 规模的网络。

注意这里的链前 cnt 初始值要设定为 1 1 1,方便通过异或操作查找反向边(这样可以使第一条边的编号为偶数, 2 n ⊕ 1 = 2 n + 1 , ( 2 n + 1 ) ⊕ 1 = 2 n 2n \oplus 1=2n+1,(2n+1)\oplus 1=2n 2n1=2n+1,(2n+1)1=2n)。用 pre 数组记录当前的增广路,flow 数组记录当前增广路上的流量。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;const ll maxn=5005;
int n,m,s,t,cnt=1,head[maxn],pre[maxn];
ll flow[maxn]/*记录到x的最大可行流*/,ans;
struct edge{int to,nxt;ll c;}e[maxn*2];
bool vis[maxn],flag[205][205];void add(int x,int y,ll z){e[++cnt]={y,head[x],z},head[x]=cnt;}bool bfs()
{for(int i=1;i<=n;i++) vis[i]=0;queue<int> q;vis[s]=1,q.push(s),flow[s]=LLONG_MAX;while(!q.empty()){int x=q.front();q.pop();for(int i=head[x];i;i=e[i].nxt){if(!e[i].c) continue;if(vis[e[i].to]) continue;flow[e[i].to]=min(flow[x],e[i].c),pre[e[i].to]=i,q.push(e[i].to),vis[e[i].to]=1;if(e[i].to==t) return 1;}}return 0;
}void ek()
{int x=t;while(x!=s) e[pre[x]].c-=flow[t],e[pre[x]^1].c+=flow[t],x=e[pre[x]^1].to;ans+=flow[t];
}int main()
{cin>>n>>m>>s>>t;for(int i=1,u,v,w;i<=m;i++) cin>>u>>v>>w,add(u,v,w),add(v,u,0);while(bfs()) ek();cout<<ans;return 0;
}

Dinic 算法

先通过 BFS,把图根据结点到源点的距离分层,只按照层数递增的方向增广。注意每次增广后都要重新将图分层。

为了保证 Dinic 算法的时间复杂度正确性,我们需要引入当前弧优化。如果一条边 ( u , v ) (u,v) (u,v) 的容量已经用完,或 v v v 的后侧已经增广至阻塞,则 u u u 的流量无需流向出边 ( u , v ) (u,v) (u,v)。对于每个结点,维护它的出边中第一个需要尝试流出的出边。维护的这个指针称为当前弧。由于我们的边是顺次遍历的,所以当遍历到第 i i i 条边时,前面的边一定已经不能继续流,直接修改新的当前弧 now[x]=i

还可以用多路增广的方法优化时间复杂度。在某点找到一条增广路后,如果还有剩余流量,继续从该点寻找增广路。

DFS 过程中,对于当前结点 x x x,它可以分给后面结点最多 f max ⁡ f_{\max} fmax 流量;对于当前访问的边 ( u , v ) (u,v) (u,v),分配的流量是最大流量与已经用的流量之差与边的容量取 min ⁡ \min min 的结果。

最坏时间复杂度为 O ( V 2 E ) O(V^2E) O(V2E)

#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;const int maxn=5005;
int n,m,s,t,cnt=1,head[maxn],now[maxn];
ll flow[maxn],ans,dis[205];
struct edge{int to,nxt;ll c;}e[maxn*2];void add(int x,int y,ll z){e[++cnt]={y,head[x],z},head[x]=cnt;}bool bfs()
{for(int i=1;i<=n;i++) dis[i]=LLONG_MAX;queue<int> q;q.push(s);dis[s]=0,now[s]=head[s];while(!q.empty()){int x=q.front();q.pop();for(int i=head[x];i;i=e[i].nxt)if(e[i].c>0&&dis[e[i].to]==LLONG_MAX){q.push(e[i].to),now[e[i].to]=head[e[i].to],dis[e[i].to]=dis[x]+1;if(e[i].to==t) return 1;}}return 0;
}int dfs(int x,ll mxf)//mxf是能给后面点分配的最大流量
{if(x==t) return mxf;ll sum=0;//sum是从x点实际分配出的流量for(int i=now[x];i;i=e[i].nxt){now[x]=i;if(e[i].c>0&&dis[e[i].to]==dis[x]+1){int ff=dfs(e[i].to,min(mxf-sum,e[i].c));e[i].c-=ff,e[i^1].c+=ff,sum+=ff;if(ff==mxf) return ff;}}return sum;
}signed main()
{cin>>n>>m>>s>>t;for(int i=1,u,v,w;i<=m;i++) cin>>u>>v>>w,add(u,v,w),add(v,u,0);while(bfs()) ans+=dfs(s,LLONG_MAX);cout<<ans;return 0;
}

最小费用最大流问题

( u , v ) (u,v) (u,v) 流量为 f ( u , v ) f(u,v) f(u,v) 时,花费的费用为 f ( u , v ) × w ( u , v ) f(u,v)\times w(u,v) f(u,v)×w(u,v),要求在最大化 ∑ ( u , v ) ∈ E f ( u , v ) \sum\limits_{(u,v)\in E}f(u,v) (u,v)Ef(u,v) 的情况下最小化 ∑ ( u , v ) ∈ E f ( u , v ) × w ( u , v ) \sum\limits_{(u,v)\in E} f(u,v)\times w(u,v) (u,v)Ef(u,v)×w(u,v),该问题即最小费用最大流问题。

SSP 算法

SSP(Successive Shortest Path)算法,思想是每次寻找费用最小的增广路进行增广,直到图上不存在增广路为止。

注意图中不能存在单位费用为负的圈。

具体实现就是把 EK/Dinic 算法中 BFS 找增广路的过程用 SPFA 代替,同时反向边的花费为负。时间复杂度 O ( V E f max ⁡ ) O(VEf_{\max}) O(VEfmax)

以下是基于 EK 算法的实现:

#include <bits/stdc++.h>
using namespace std;const int maxn=5005,maxm=1e5+5;
struct edge{int to,nxt,c,w;}e[maxm];
int head[maxn],pre[maxn],dis[maxn],cnt=1,n,m,s,t,mxf,minc,flow[maxn];
bool vis[maxn];void add(int x,int y,int z,int q){e[++cnt]=(edge){y,head[x],z,q},head[x]=cnt;}bool spfa()
{queue<int> q;for(int i=1;i<=n;i++) dis[i]=INT_MAX,vis[i]=0;q.push(s),dis[s]=0,flow[s]=INT_MAX,vis[s]=1,pre[t]=-1;while(!q.empty()){int x=q.front();q.pop(),vis[x]=0;for(int i=head[x];i;i=e[i].nxt)if(e[i].c&&dis[e[i].to]>dis[x]+e[i].w){dis[e[i].to]=dis[x]+e[i].w,pre[e[i].to]=i,flow[e[i].to]=min(flow[x],e[i].c);if(!vis[e[i].to]) q.push(e[i].to),vis[e[i].to]=1;}}return pre[t]!=-1;
}void ek()
{while(spfa()){int x=t;mxf+=flow[t],minc+=flow[t]*dis[t];while(x!=s) e[pre[x]].c-=flow[t],e[pre[x]^1].c+=flow[t],x=e[pre[x]^1].to;// cout<<flow[t]<<' '<<dis[t]<<endl;}
}int main()
{cin>>n>>m>>s>>t;for(int i=1,u,v,w,c;i<=m;i++) cin>>u>>v>>w>>c,add(u,v,w,c),add(v,u,0,-c);ek();cout<<mxf<<' '<<minc;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/173274.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue项目搭建及使用vue-cli创建项目、创建登录页面、与后台进行交互,以及安装和使用axios、qs和vue-axios

目录 1. 搭建项目 1.1 使用vue-cli创建项目 1.2 通过npm安装element-ui 1.3 导入组件 2 创建登录页面 2.1 创建登录组件 2.2 引入css&#xff08;css.txt&#xff09; 2.3 配置路由 2.5 运行效果 3. 后台交互 3.1 引入axios 3.2 axios/qs/vue-axios安装与使用 3.2…

SpringCloud 微服务全栈体系(五)

第七章 Feign 远程调用 先来看我们以前利用 RestTemplate 发起远程调用的代码&#xff1a; 存在下面的问题&#xff1a; 代码可读性差&#xff0c;编程体验不统一 参数复杂 URL 难以维护 Feign 是一个声明式的 http 客户端&#xff0c;官方地址&#xff1a;https://github.…

【C++】缺省参数及函数重载

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 1. 缺省参数1.1 缺省…

迭代器的封装与反向迭代器

一、反向迭代器 在list模拟实现的过程中&#xff0c;第一次接触了迭代器的封装&#xff0c;将list的指针封装成了一个新的类型&#xff0c;并且以迭代器的基本功能对其进行了运算符重载 反向迭代器是对正向迭代器的封装&#xff0c;并且体现了泛型编程的思想&#xff0c;任意…

win10虚拟机安装教程

目录 1、安装VMware 10、12、16都可以&#xff0c;看个人选择 2、开始安装系统&#xff08;以vm16为例&#xff09; 3、在虚拟机中安装win10 完成 1、安装VMware 10、12、16都可以&#xff0c;看个人选择 下面链是我虚拟机安装包&#xff0c;需要可以下载。 YR云盘 软件安…

华为OD机考算法题:高效的任务规划

题目部分 题目高效的任务规划难度难题目说明 你有 n 台机器编号为 1 ~ n&#xff0c;每台都需要完成一项工作&#xff0c; 机器经过配置后都能独立完成一项工作。 假设第 i 台机器你需要花 分钟进行设置&#xff0c; 然后开始运行&#xff0c; 分钟后完成任务。 现在&#x…

虚拟机构建部署单体项目及前后端分离项目

目录 一.部署单体项目 1.远程数据库 1.1远程连接数据库 1.2 新建数据库运行sql文件 2.部署项目到服务器中 3.启动服务器运行 二.部署前后端分离项目 1.远程数据库和部署到服务器 2.利用node环境启动前端项目 3.解决主机无法解析服务器localhost问题 方法一 ​编辑 方…

Illustrator 2024(AI v28.0)

Illustrator 2024是一款功能强大的矢量图形编辑软件&#xff0c;由Adobe公司开发。它是设计师、艺术家和创意专业人士的首选工具&#xff0c;用于创建和编辑各种矢量图形、插图、图标、标志和艺术作品。 以下是Adobe Illustrator的主要功能和特点&#xff1a; 矢量图形编辑&…

命令模式——让程序舒畅执行

● 命令模式介绍 命令模式&#xff08;Command Pattern&#xff09;&#xff0c;是行为型设计模式之一。命令模式相对于其他的设计模式来说并没有那么多条条框框&#xff0c;其实并不是一个很“规矩”的模式&#xff0c;不过&#xff0c;就是基于一点&#xff0c;命令模式相对于…

实战授权码登录流程

我是经常阅读公众号优质文章&#xff0c;也经常体验到公众号的授权登录功能。今天就来实现下&#xff0c;流程图如下 效果图 后端接口 主要用来接收微信服务器推送的公众号用户触发的事件、生成和验证授权码的有效性 解析微信服务器推送的事件通知 public String login(Se…

MySQL 概述 数据库表操作 数据增删改

目录 MySQL概述前言安装与配置MySQL登录与卸载 数据模型概述SQL简介SQL通用语法简介SQL分类 数据库设计(数据库操作)-DDL数据库操作查询数据库 show databases、select database()创建数据库 create database使用数据库 use删除数据库 drop database 图形化工具连接数据库操作数…

Node.js中的单线程服务器

为了解决多线程服务器在高并发的I/O密集型应用中的不足&#xff0c;同时避免早期简单单线程服务器的性能障碍&#xff0c;Node.js采用了基于"事件循环"的非阻塞式单线程模型&#xff0c;实现了如下两个目标&#xff1a; &#xff08;1&#xff09;保证每个请求都可以…

通过el-tree 懒加载树,创建国家地区四级树

全国四级行政地区树数据库sql下载路径&#xff1a;【免费】全国四级地区(省市县)数据表sql资源-CSDN文库https://download.csdn.net/download/weixin_51722520/88469807?spm1001.2014.3001.5503 我在后台获取地区信息添加了限制&#xff0c;只获取parentid为当前的地…

[AUTOSAR][诊断管理][ECU][$34] 下载请求

文章目录 一、简介二、服务请求报文定义肯定响应支持的NRC三、示例代码34_req_dowload.c一、简介 RequestDownload(0x34)—— 下载请求 这个服务主要是用来给ECU下载数据的,最常见的应用就是在bootloader中,程序下载工具会发起下载请求,以完成ECU程序的升级。 二、服务…

计算线阵相机 到 拍摄产品之间 摆放距离?(隐含条件:保证图像不变形)

一物体被放置在传送带上&#xff0c;转轴的直径为100mm。已知线阵相机4K7u&#xff08;一行共4096个像素单元&#xff0c;像素单元大小7um&#xff09;&#xff0c;镜头35mm&#xff0c;编码器2000脉冲/圈。保证图像不变形的条件下&#xff0c;计算相机到产品之间 摆放距离&…

国际阿里云CDN加速OSS资源教程!

当您需要加速OSS上的静态资源时&#xff0c;可以通过阿里云CDN加速OSS域名&#xff0c;实现静态资源的访问加速。本文详细介绍了通过CDN控制台实现OSS加速的操作流程和应用场景。 客户价值 阿里云OSS可提供低成本的存储&#xff0c;CDN可以实现静态资源加速分发。使用OSS作为C…

Linux学习第24天:Linux 阻塞和非阻塞 IO 实验(一): 挂起

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 在正式开始今天的笔记之前谈一下工作中遇见的一个问题。 本篇笔记主要学习Linux 阻塞和非阻塞 IO 实验&#xff0c;主要包括阻塞和非阻塞简介、等待队列、轮询、…

05.大模型大数据量

文章目录 大模型顿悟时刻&#xff1a;Emergent Ability&#xff08;涌动现象&#xff09;Calibration Inverse Scaling PrizeSwitch Transformers 大数据量数据预处理去重 模型大小与训练数据的选择Instruction-tuningHuman TeachingKNN LM 部分截图来自原课程视频《2023李宏毅…

NewStarCTF2023week4-Nmap

题目要我们找出Nmap扫描得到所有的开放端口 Nmap通常用于直接扫描目标主机&#xff0c;而不是直接扫描pcap文件。 那么这里我们还是使用wireshark来分析&#xff0c;使用过滤器&#xff1a; tcp.flags.syn 1 and tcp.flags.ack 1 这个过滤条件可以筛选出TCP端口开放的数据…

Games104现代游戏引擎笔记 网络游戏架构基础

挑战1:网络同步 挑战2:是网络的可靠性&#xff0c;包括应对网络的延迟&#xff0c;丢包和掉线 挑战3: 反作弊和安全系统&#xff0c;因为网络游戏的本质是经济系统 挑战4:多样性(不同设备&#xff0c;不同服务器)&#xff0c;在不停服的情况下热更新 挑战5:大量人数时对高并发…