网络最大流Dinic
1.什么是网络最大流
形象的来说,网络最大流其实就是这样一个生活化的问题:现在有一个由许多水管组成的水流系统,每一根管道都有自己的最大通过水流限制(流量),超过这个限制水管会爆(你麻麻就会来找你喝茶qwq)。现在,给定你一个出水口(原点),一个出水口(汇点),求这个网络中水流量的最大值。
????看起来很简单对不对?在我们看起来的确是这样的,而这部分的难点也确实不在思路上,而是在于算法设计以及代码实现上。
2.怎么求解网络最大流
首先想明白一件事情,对于一个节点来说,他接受的流量一定小于等于他给出的流量之和,否则,水管一定会爆掉。而对于一个节点来说,他接受的流量有可能大于任意一个他出边的流量,因为这个节点可以把接受流给出到不同的水管上,进而实现分流。
有了这两点,思路就很清晰了(贪心算):
1.首先,我们需要寻找一条可行的流量方案(此时,不一定为最大流量)。
2.然后我们依次扩展这条路径上的所有节点,看看这个节点是否还可以接受流量,直到已经满流。
3.重复上述步骤,直到没有可行流动路径。
4.此时我们累加的流量即为网络最大流,我们把这种方法称为最大流Dinic算法
3.实现细节
这种算法看起来简单,实际上实现起来会遇到许多小毛病,以及许多很难理解的代码实现,这里举一个栗子
在步骤2的时候我们采用dfs进行扩展,也称为网络最大流的扩展部分算法,需要借助到反边这样一个概念,即:两个节点A,B间有一条权值为w无向边。我们就把他拆分成一条由A指向B的有向边与一条由B指向A的有向边,其中,这两条边的权值之和为w,这样一来一回,两者相互抵消巧妙的实现了回溯
上代码:qwq
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define N 1000005
#define M 4*1000005
#define INF 0xfffffff using namespace std; int Read()//快读
{
int num=0,k=1;
char c=getchar();
while(c!='-'&&(c<'0'||c>'9')) c=getchar();
if(c=='-')
{
k=-1;
c=getchar();
}
while(c<='9'&&c>='0')
{
num=(num<<3)+(num<<1)+c-'0';
c=getchar();
}
return num*k;
} struct node
{
int from;
int to;
int v;
int next;
}; node edge[2*M];
int cnt_edge=1,n,m,s,t;
long long ans=0;
int last[N],deep[N]; void add_edge(int u,int v,int w)
{
edge[++cnt_edge].from=u;
edge[cnt_edge].to=v;
edge[cnt_edge].v=w;
edge[cnt_edge].next=last[u];
last[u]=cnt_edge;
} bool bfs() //判断是否有通路
{
memset(deep,-1,sizeof(deep));
deep[s]=0;
queue<int >q;
q.push(s);
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=last[now];i;i=edge[i].next)
{
int j=edge[i].to;
if(deep[j]==-1&&edge[i].v)
{
deep[j]=deep[now]+1;
q.push(j);
}
}
}
return deep[t]!=-1;
} int dfs(int now,int flow) //flow为当前流量
{
if(now==t) return flow;
int delta=flow; //delta是剩余流量,就是流不下去的流量 for(int i=last[now];i;i=edge[i].next)
{
int to=edge[i].to;
if((deep[to]==(deep[now]+1))&&edge[i].v > 0)
{
int d=dfs(to,min(delta,edge[i].v));
if(!d) deep[to] = 1e9; //剪枝优化,当前点无法下流
edge[i].v-=d;edge[i^1].v+=d;delta-=d;//流下去,反边+d,方便回流 if(!delta) break;
}
}
return flow-delta; //返回这里留下去了多少 ,即当前点的最大流量
} int main ()
{
n=Read();m=Read();s=Read();t=Read(); int u,v,w; for(int i=1;i<=m;i++)
{
u=Read();v=Read();w=Read();
add_edge(u,v,w);add_edge(v,u,0);
} while(bfs()) ans+=dfs(s,INF); printf("%lld\n",ans);
return 0;
}
看完关注哦~
网络最大流Dinic的更多相关文章
- P3376 【模板】网络最大流dinic算法
P3376 [模板]网络最大流 题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点 ...
- 网络最大流 Dinic算法
前言 看到网上好多都用的链式前向星,就我在用 \(vector\) 邻接表-- 定义 先来介绍一些相关的定义.(个人理解) 网络 一个网络是一张带权的有向图 \(G=(V,E)\) ,其中每任意一条边 ...
- 网络最大流dinic模板
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using ...
- luogu3376 【模板】网络最大流 dinic
当前弧优化 #include <iostream> #include <cstring> #include <cstdio> #include <queue& ...
- P3376 【模板】网络最大流 dinic详解
dinic的核心在于分层和多路增广. 分层的意思是,对于图用bfs搜出每一层,避免出现dfs深度过深的情况. 多路增广,利用的是dfs的回溯性质,这样就可以在一个点增广出它的所有流量. #includ ...
- 算法模板——Dinic网络最大流 2
实现功能:同Dinic网络最大流 1 这个新的想法源于Dinic费用流算法... 在费用流算法里面,每次处理一条最短路,是通过spfa的过程中就记录下来,然后顺藤摸瓜处理一路 于是在这个里面我的最大流 ...
- 算法模板——Dinic网络最大流 1
实现功能:同sap网络最大流 今天第一次学Dinic,感觉最大的特点就是——相当的白话,相当的容易懂,而且丝毫不影响复杂度,顶多也就是代码长个几行 主要原理就是每次用spfa以O(n)的时间复杂度预处 ...
- 图论算法-网络最大流【EK;Dinic】
图论算法-网络最大流模板[EK;Dinic] EK模板 每次找出增广后残量网络中的最小残量增加流量 const int inf=1e9; int n,m,s,t; struct node{int v, ...
- 网络最大流算法—Dinic算法及优化
前置知识 网络最大流入门 前言 Dinic在信息学奥赛中是一种最常用的求网络最大流的算法. 它凭借着思路直观,代码难度小,性能优越等优势,深受广大oier青睐 思想 $Dinic$算法属于增广路算法. ...
随机推荐
- C#中部分重点前端设置问题
背景 在工作及学习过程中经常会遇到一些奇怪的需求,这里便会记录我遇到的奇怪需求及解决方法. 内容 一.动态设置页面标题 1.前端设置 JS代码: document.title="这是一个标题 ...
- 深入理解Java中的装箱与拆箱
一.Java数据类型 1.在说装箱与拆箱之前,先说一下Java的基本数据类型,Java从数据类型上可以划分为值类型与引用类型,值类型是四类八种,分别是: 整数型:byte̵,short̵,int̵,l ...
- 5分钟掌握企业LVM磁盘划分
逻辑卷管理LVM是一个多才多艺的硬盘系统工具.无论在Linux或者其他类似的系统,都是非常的好用.传统分区使用固定大小分区,重新调整大小十分麻烦.但是,LVM可以创建和管理“逻辑”卷,而不是直接使用物 ...
- Ubuntu中的launcher
最近在ubuntu系统中下载了最新版的eclipse,在一个临时文件夹中解压了eclipse压缩包,然后打开eclipse,按平时常规做法,我在launcher里右键点击eclipse,选择“锁定到启 ...
- Java SPI详细的例子
先翻一个来自于Baeldung的介绍: 为了更通俗易懂我就没有直译,如果有不严谨的地方请大神指教. JavaSPI的定义 Java SPI defines four main components S ...
- get、post请求方式在postman中使用步骤
1.get请求方式:不需要借助任何工具,在浏览器里面就可以发送请求,直接在浏览器里面输入访问 url?参数名=参数值 url?parma=abc&name=abcd 2.post请 ...
- oracle之序列
序列 15.1 序列是生成唯一整数值的结构,它的典型用途是用于主键值. 结合真题演示伪列nextval, currval用法 CREATE SEQUENCE dept_deptnoINCREMENT ...
- [LeetCode]96. 不同的二叉搜索树(DP,卡特兰数)
题目 给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种? 示例: 输入: 3 输出: 5 解释: 给定 n = 3, 一共有 5 种不同结构的二叉搜索树: 1 3 3 2 1 \ ...
- STL_Vector(向量)
向量Vector 头文件 #include<vector> 作用: vector是一种顺序容器,与数组类似,但与之不同的是vector并不需要开辟内存空间,其类似于每存一个变量便开一个空间 ...
- Jaskson精讲第7篇-类继承关系下的JSON序列化与反序列化JsonTypeInfo
Jackson是Spring Boot(SpringBoot)默认的JSON数据处理框架,但是其并不依赖于任何的Spring 库.有的小伙伴以为Jackson只能在Spring框架内使用,其实不是的, ...