网络流初步

文章目录

  • 网络流初步
    • 概念介绍
    • 最大流
    • 费用流

概念介绍

网络流不同之处在于它的本质图论,但是把图论的某些概念换了一个说法而已,初步只要了解网络流的各个概念就可以明白的很快。

下述概念是本人自己定义的,对于网络流的题目做的还不多,后续会更正。

首先需要理解:网络流其实是在一个有向图中,从某个原点开始放水,水沿着管道最后流向汇点的过程,基于此就可以很好的理解一些概念和定理,而不需要十分严谨的证明(因为证明意义不大

流网络: 对于一个 G(V,E)G(V,E)G(V,E) 的单向图,我们称为流网络

容量C: 点和点之间的边权成为容量

流量F: 通俗点说,点与点之间流过的水流量,和物理定义流量一致。一个很显然的性质:F≤CF\le CFC 即流量不能超过容量

原点和汇点: 水流出的点,和水流入的点。

可行流: 全称可以流进去的流量,F(u,v)F(u,v)F(u,v) 表示从 u 点流到 v 点的流量

流网络的可行流:即从原点或者汇点流入或者流出的总流量 ∣F∣|F|F

最大流: 全称最大可行流,比较抽象,实际意义就是:从原点可以流出的最大流量,或者是汇集到汇点的最大流量。

残留网络: 对于一个每条边都确定流量F的流网络,如果存在某条边 C−F>0C-F>0CF>0 ,即如果可以的话,还可以从 u→vu\to vuv 流动 C−FC-FCF 的水,那么我们将这些差值重新构造一张图,形成的网络被称为残留网络,十分形象,同时还会建立反向边,不过权值变成 −F-FF ,可以理解为水反向流动。此时构成完整的残存网络。

增广路: 在残存网络中,存在一条路径使得从S到T,该条路径流过的水>0,也就是路径最小值大于零,则称为该条路径成为增广路。

:对于原点S 和 汇点T,我们通过划分将点集分成两部分,满足 S点集中点可以从S到达,T点集中点可以到达T,但是T和S不能在一个集合,此时我们成为是流网络中的一个割。

割的容量: 即连接点集 S 和点集 T 的边权的容量

割的流量: 同上,边权的流量

最小割: 全称最小割的容量。

结论

  • 如果残留网络不存在增广路,此时流网络的可行流最大,即最大流

    证明: 主观十分好理解:如果不存在一种路径使得水从原点流到汇点,那么此时说明不能再流动,那么此时就是最大流量

    证明充要:也很显然,既然是最大流量,那么就不可能存在让自己流量在增加的路

  • 如果残留网络不存在增广路,那么一定存在一种割的两个点集 S,TS,TS,T,满足 ∣F∣=∑u∈S,v∈Tc(u,v)|F|=\sum_{u\in S,v\in T} c(u,v)F=uS,vTc(u,v)

    证明:现在画图更好理解这句话的意思:
    在这里插入图片描述

    公式含义就是粉色框的边权的容量要等于流网络的可行流。 y总的证明:

    我们这样构造 S点集:在残留网络GfG_fGf 中所有从S点出发边权容量不是 0 的点,剩余点归算于T点,那么对于这割的容量就是0,可以发现,这样的集合是可以构造出来的,因为有这个GfG_fGf 不存在增广路的条件,那么所有的路径至少存在一个边权容量为0。

    那么因为每个割的残留网络容量为0,那么说明每条边都是某条流过的路径的最小值(或者是某些最小值的和,因为可能会存在距离S更近的某条边残余容量为0,这些流量之后恰好分开流向后面的最小值们,本质上是还是所有流过的路径最小值的贡献总和,可以理解为是所有的最小值边成为了割),也就是该条路径的流量,那么将这些流量加起来就是总流量。因为从S点流出的流量必须经过割中的所有边权才能到达T,又因为每个边的容量等于流量,所以满足 ∣F∣=∑C(u,v)|F|=\sum C(u,v)F=C(u,v)

  • 如果存在两个点集 S,TS,TS,T,满足 ∣F∣=∑u∈S,v∈Tc(u,v)|F|=\sum_{u\in S,v\in T} c(u,v)F=uS,vTc(u,v),那么∣F∣|F|F 一定是最大流

证明:很显然,因为割的每条边的流量完全等于容量(由2可知(因为不存在增广路)),试想,我们将连接两个点集的之间割的容量全部得到了(S,T 之间可传递的最大容量),那么此时的流量和就是最大流。

  • 最大流=最小割

    由上面的三个证明便可以得到,最大流 →\to 不存在增广路 →\to 最小割 →\to 最大流

这是最重要的证明,便于以后的建边和理解。

最大流

算法实现:

EK算法

算法思想:在图中不断找增广路,然后对边更改删掉增光路,对答案造成贡献,最后不存在增广路就是答案。时间复杂度:O(nm2)O(nm^2)O(nm2),时间复杂度不会证明,不过可以满足 n<10000 以下的级别

模板:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int read(){int x;scanf("%lld",&x);return x;}
const int B=1e6+10;
int p;
int n,m,S,T;
int head[1010];
int cnt;
struct node
{int u,v,nxt,w;
}e[B<<1];
void modify(int u,int v,int w)
{e[cnt].nxt=head[u];e[cnt].v=v;e[cnt].w=w;head[u]=cnt;cnt++;
} 
void add(int u,int v,int w)
{modify(u,v,w);modify(v,u,0);
}
int d[1010];
int pre[1010];
int vis[1010];
int inf=0x3f3f3f3f;
bool bfs()
{queue<int>q;memset(vis,0,sizeof(vis));q.push(S); vis[S]=1; d[S]=inf; while (!q.empty()){int u=q.front();q.pop();for (int i=head[u];i!=-1;i=e[i].nxt){int v=e[i].v;if (vis[v] || e[i].w==0) continue;d[v]=min(d[u],e[i].w);vis[v]=1;pre[v]=i;if (T==v) return 1;q.push(v);}}return 0;
}
int EK()
{int r=0;while (bfs()){r+=d[T];for (int i=T;i!=S;i=e[pre[i]^1].v){e[pre[i]].w-=d[T];e[pre[i]^1].w+=d[T];}}return r;
}
void work()
{cin>>n>>m>>S>>T;memset(head,-1,sizeof(head));for (int i=1;i<=m;i++){int u=read(),v=read(),c=read();add(u,v,c);}cout<<EK();
}
signed main()
{p=1;while (p--) work();return 0;
}

网络流细节

双向建边的时候需要注意的地方

  • cnt从 0 开始,不是1
  • for 循环里,边界 i!=-1 而不是 i!=0

费用流

费用流被称为:最小费用最大流

每个流量上又添加了一个单位流量花费。要求在最大流的情况下花费最小。

写法:把bfs找增广路,改写成SPFA找增广路就可以

证明:

最终可以从s点到达T做出贡献的路径是一定的,每条路径之间可能存在平替的现象,Bfs只是从中随便选择了几条,但我们可以将其平替,如下图

在这里插入图片描述

这些路径中,存在多种方案满足条件,要想花费最小,直接贪心就可。以前之所没有想明白,就可这张图一样,我想的是如果先把 6 的路径找出来,最后就只剩下 2 的路径才能成为8

不过我忘记了,还可以从 4 中走2,并不一定非要走4,所以这就不需要担心当前选择影响后续可选择对象的问题了,因为当前的选择不影响后续任何选择,不会导致选择对象数量发生变化,故可以直接贪心

模板

#include<bits/stdc++.h>
#define int long long
using namespace std;
int read(){int x;scanf("%lld",&x);return x;}
const int B=1e6+10;
int p;
int n,m,S,T;
int head[B];
int cnt;
struct node
{int u,v,nxt,c,w;
}e[B<<1];
void modify(int u,int v,int c,int w)
{e[cnt].nxt=head[u];e[cnt].v=v;e[cnt].c=c;e[cnt].w=w;head[u]=cnt;cnt++;
} 
void add(int u,int v,int c,int w)
{modify(u,v,c,w);modify(v,u,0,-w);
}
int d[5010];
int pre[5010];
int vis[5010];
int inf=0x3f3f3f3f;
int dis[5010];
bool bfs()
{queue<int>q;for (int i=1;i<=n;i++){vis[i]=0;dis[i]=inf;}q.push(S); vis[S]=1; d[S]=inf; dis[S]=0;while (!q.empty()){int u=q.front();q.pop();vis[u]=0;for (int i=head[u];i!=-1;i=e[i].nxt){int v=e[i].v;if (e[i].c==0) continue;if (dis[v]>dis[u]+e[i].w){dis[v]=dis[u]+e[i].w;pre[v]=i;d[v]=min(d[u],e[i].c);if (!vis[v]){vis[v]=1;q.push(v);}}}}return dis[T]!=inf;
}
void EK()
{int r=0;int sum=0;while (bfs()){r+=d[T];sum+=d[T]*dis[T];for (int i=T;i!=S;i=e[pre[i]^1].v){e[pre[i]].c-=d[T];e[pre[i]^1].c+=d[T];}}printf("%lld %lld", r,sum);
//	cout<<r<<" "<<sum<<"\n";
}
void work()
{cin>>n>>m>>S>>T;for (int i=1;i<=n;i++) head[i]=-1;for (int i=1;i<=m;i++){int u=read(),v=read(),c=read(),w=read();add(u,v,c,w);}EK();
}
signed main()
{p=1;while (p--) work();return 0;
}

r,sum);
// cout<<r<<" “<<sum<<”\n";
}
void work()
{
cin>>n>>m>>S>>T;
for (int i=1;i<=n;i++) head[i]=-1;
for (int i=1;i<=m;i++)
{
int u=read(),v=read(),c=read(),w=read();
add(u,v,c,w);
}
EK();
}
signed main()
{
p=1;
while (p–) work();
return 0;
}


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

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

相关文章

[系统架构设计师]系统架构基础知识(一)

[系统架构设计师]系统架构基础知识&#xff08;一&#xff09; 一.计算机系统基础知识 1.计算机系统概述 硬件软件及网络组成的系统 2.计算机硬件基础知识 冯 诺依曼结构&#xff1a;运算器&#xff0c;控制器&#xff0c;存储器&#xff0c;输入设备&#xff0c;输出设备 专用…

深入解析Java代理模式:灵活控制对象访问的核心技术

在日常开发中&#xff0c;我们常遇到这样的场景&#xff1a;需要控制对象访问权限、优化高成本操作&#xff0c;或给方法添加额外功能&#xff08;如日志、事务&#xff09;。代理模式&#xff08;Proxy Pattern&#xff09; 正是解决这类问题的金钥匙。作为结构型设计模式的代…

【学习笔记】Java并发编程的艺术——第9章 Java中的线程池

第9章 Java中的线程池 线程池优势&#xff1a; ①减少资源消耗 ②提高响应速度 ③统一管理 9.1 线程池的实现原理 当任务来后 ①判断核心线程池是否已满&#xff0c;若未满&#xff0c;创建一个核心线程来执行任务 ②若无空闲核心线程且核心线程已满&#xff0c;则将任务放入任…

Mybatis学习笔记(九)

常见问题与解决方案 简要描述&#xff1a;总结MyBatis-Plus开发过程中常见的问题、错误及其解决方案&#xff0c;帮助开发者快速定位和解决问题。 核心概念&#xff1a; 常见错误&#xff1a;开发中经常遇到的错误类型性能问题&#xff1a;性能相关问题的排查和解决配置问题&am…

数据类型 list

一、介绍类似于数组&#xff0c;顺序表&#xff0c;deque结构图特点&#xff1a;元素有序&#xff0c;元素允许重复由于头尾高效插入删除&#xff0c;可以模拟栈&#xff0c;队列二、常见 list 命令1、lpush key elem [elem ...]头插元素&#xff0c;返回值列表长度2、lrange k…

pyqt5无法显示opencv绘制文本和掩码信息

背景&#xff1a;pyqt5无法显示opencv绘制的标签和mask&#xff1b;我们在使用YOLO做实例分割做推理时&#xff0c;会使用opencv做后处理结果绘制&#xff08;含标签绘制和掩码绘制&#xff09;&#xff1b;结果opencv绘制的解码却无法在pyqt的解码上面显示。pyqt转换代码如下&…

如何生成严格递增的分布式id?

本文字数&#xff1a;2604字预计阅读时间&#xff1a;15分钟01引言在现有分布式系统中&#xff0c;面对增长迅速的业务数据&#xff0c;id生成一直是非常重要的一环。而分布式系统的id生成方案需要满足几个重要特性&#xff1a;容错高可用、高性能高并发、全局唯一。02技术背景…

【LeetCode】二叉树相关算法题

目录1、二叉树介绍【1】核心概念【2】关键特性2、算法题【1】二叉树的前序遍历【2】二叉树的后序遍历1、二叉树介绍 【1】核心概念 结构含义节点结构二叉树由节点组成&#xff0c; 每个节点包含一个数据元素和最多两个子节点&#xff1a;左子节点和右子节点根节点树的顶部节点…

Vulnhub Deathnote靶机复现攻略

一、靶机安装 下载地址&#xff1a;https://download.vulnhub.com/deathnote/Deathnote.ova 下载好后使用VB打开&#xff0c;配置如下 二、主机发现 使用相同连接方式的kali进行后续操作(172.16.2.7)根据mac地址进行确认。 nmap -sn 172.16.2.1/24 三、端口扫描 端口开放了…

DevEco Studio 6.0.0 元服务页面跳转失败

背景&#xff0c;我使用最新的编辑器DevEco Studio 6.0.0&#xff0c;编写一个元服务&#xff0c;发现使用跳转页面的时候失败了&#xff01;然后查看官方文档&#xff0c;两种方式都测试了&#xff0c;发现都不行。 方法1&#xff1a;Navigation路由跳转无效&#xff0c;见官方…

docker重启或系统重启后harbor自动启动

docker重启或系统重启后harbor自动启动docker重启或系统重启后harbor自动启动方法 1&#xff1a;在 docker-compose.yml 中配置重启策略&#xff08;推荐&#xff09;方法 2&#xff1a;创建 Systemd 服务&#xff08;更可靠&#xff09;方法 3&#xff1a;使用 Docker 的 Rest…

OpenZeppelin Contracts 架构分层分析

OpenZeppelin Contracts 是一个面向以太坊&#xff08;及兼容 EVM 的区块链&#xff09;生态系统的​​模块化、安全性优先、标准兼容的智能合约库​​。其内部代码按照功能职责与抽象层级&#xff0c;可系统性地划分为多个逻辑层次。理解这些层次及其依赖关系&#xff0c;对于…

Java-JVM的内存模型

一.JVM内存模型JVM内存模型可以从进程生命周期和线程生命周期1.线程生命周期每个线程都会有自己各自一份数据&#xff0c;不会存在线程安全问题1.程序计数器指示当前线程执行的字节码指令的行号&#xff0c;以便线程执行时可以回到正确的位置2.虚拟机栈线程私有的&#xff0c;与…

Highcharts Dashboards | 打造企业级数据仪表板:从图表到数据驾驶舱

企业日常决策、产品运营、业务监控&#xff0c;越来越依赖数据驱动。而仪表板&#xff08;Dashboard&#xff09;作为汇总展示多维度信息的“数据驾驶舱”&#xff0c;已成为企业可视化的核心场景之一。如果你正在寻找一款能够快速、灵活、安全构建仪表板的前端图表工具&#x…

基于Java的Markdown转Word工具(标题、段落、表格、Echarts图等)

项目源于我们开发的一款基于大模型的报告生成工具。由于需要将 Markdown 格式的内容导出为 Word 文档&#xff0c;而市面上缺乏合适的现成工具&#xff0c;所以决定自己开发一个Markdown转Word的工具。 &#x1fa77;源码地址&#xff1a;daydayup-zyn/md2doc-plus &#x1f…

Unity:PlayerPrefs笔记

写在前面&#xff1a;写本系列(自用)的目的是回顾已经学过的知识、记录新学习的知识或是记录心得理解&#xff0c;方便自己以后快速复习&#xff0c;减少遗忘。一、PlayerPrefs的基本方法1、存储相关PlayerPrefs的数据存储类似于键值对存储&#xff0c;一个键对应一个值。Unity…

SQL tutorials

SQL Literature SQL运行在资料库管理系统&#xff08;Database Management System&#xff09;&#xff0c;如MySQL&#xff0c;Postgre SQL&#xff0c;Microsoft SQL Server&#xff0c; Oracle&#xff0c;etc。 SQL练习平台&#xff1a;https://sqliteviz.com/ EXAMPLE SQL…

MySQL快速恢复数据的N种方案完全教程

目录 1. 理解MySQL数据恢复的核心逻辑 1.1 数据丢失的常见场景 1.2 MySQL的“救命稻草”:关键文件和机制 2. 方案一:利用全量备份+binlog实现点对点恢复 2.1 准备工作 2.2 恢复步骤 2.3 实战案例 3. 方案二:利用InnoDB的崩溃恢复机制 3.1 崩溃恢复的原理 3.2 恢复步…

双屏加固笔记本电脑C156-2:坚固与高效的完美融合

在当今数字化时代&#xff0c;笔记本电脑已成为人们工作和生活中不可或缺的工具。然而&#xff0c;对于一些特殊行业和恶劣环境下的应用场景&#xff0c;普通笔记本电脑往往难以满足需求。此时&#xff0c;具备坚固耐用、高性能等特点的加固笔记本电脑应运而生。鲁成伟业的双屏…

Jenkins 环境部署

下载相关软件&#xff1a;Jenkins 的安装和设置 相关工具&#xff1a; Git : Git - Downloads java 17: Java Archive Downloads - Java SE 17.0.12 and earlier python : Download Python | Python.org jenkins、jenkins.war : Jenkins 的安装和设置 将所有软件安装后&am…