【Luogu P3376】网络最大流
Luogu P3376
最大流是网络流模型的一个基础问题。
网络流模型就是一种特殊的有向图。
概念:
- 源点:提供流的节点,类比成为一个无限放水的水厂
- 汇点:接受流的节点,类比成为一个无限收水的小区
- 弧:类比为水管
- 弧的容量:类比为水管的容量;用函数\(c(x,y)\)表示弧\((x,y)\)的容量
- 弧的流量:类比为当前在水管中水的量;用函数\(f(x,y)\)表示弧\((x,y)\)的流量
- 弧的残量:即容量-流量
- 容量网络:对于一个网络流模型,每一条弧都给出了容量,则构成一个容量网络。
- 流量网络:对于一个网络流模型,每一条弧都给出了流量,则构成一个流量网络。
- 残量网络:对于一个网络流模型,每一条弧都给出了残量,则构成一个残量网络。最初的残量网络就是容量网络。
对于网络流模型\(G=(V,E)\)(\(V\)为点集,\(E\)为边集)有如下性质:
- 流量守恒:除了源点与汇点之外,流入任何节点的流一定等于流出该节点的流
- 容量限制:\(\forall (x,y) \in E,有0<=f(x,y)<=c(x,y)\)
- 斜对称性:\(\forall (x,y) \in E,有f(x,y)=-f(y,x).\)类似于函数奇偶性中的奇函数,或者是矢量的方向。
最大流问题,用通俗的方式解释就是从源点S到汇点T输送流量,询问最多有多少流量能输送到汇点。
对于这样的问题,我们引入一些新概念:
- 增广路:一条从源点到汇点的路径\(R\),满足\(\forall (x,y) \in R, c(x,y)-f(x,y)>0.\)即残量为正数
- 最大流最小割定理:网络流模型达到最大流,当且仅当残量网络中没有任何增广路(并不完整,但是足够了)
\(Ford-Fulkerson\)方法:每一次寻找一条增广路径。根据木桶原理,该增广路的最大流量\(f_{max}<=min(c(x,y)-f(x,y))\)。据此从源点发送流量至汇点并修改路径上所有弧的残量,直到无法找到增广路为止。
\(Edmons-Karp\)算法:基于\(Ford-Fulkerson\)方法的一种算法,核心就是利用\(BFS\)搜索源点到汇点的最短增广路,根据\(Ford-Fulkerson\)方法修改残量网络。复杂度最坏是\(O(nm^2)\)
所以其实我们在求最大流相关问题时,其实只利用到了残量网络,流量和容量一般并不需要记录。
关键点:有时候在求最大流时我们可能需要缩减一条边的流量,所以我们引入了反向边。当我们选用了一条反向边时,相当于缩减正向边的流量。很容易发现反向边的残量等于正向边的流量(最多恰好抵消正向流量)。
这样就能保证算法的正确性。
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
struct data
{
int to,next,val;
}e[2*100005];
int cnt,head[10005],prep[10005],pree[10005],flow[10005],ans;
queue<int> que;
int n,m,s,t,u,v,w;
void add(int u,int v,int w)
{
e[++cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt;
e[cnt].val=w;
}
int bfs(int s,int t)
{
while (!que.empty()) que.pop();
flow[s]=0x3f3f3f3f;//flow记录的是在增广路上经过该点的流量
que.push(s);
for (int i=1;i<=n;i++)
{
prep[i]=-1;//用于记录前驱节点
pree[i]=0;//用于记录前驱边的编号
}
prep[s]=0;
while (!que.empty())
{
int now=que.front();
que.pop();
if (now==t) break;
for (int i=head[now];i;i=e[i].next)
{
if (e[i].val>0&&prep[e[i].to]==-1)
{
que.push(e[i].to);
flow[e[i].to]=min(flow[now],e[i].val);
pree[e[i].to]=i;
prep[e[i].to]=now;
}
}
}
if (prep[t]!=-1) return flow[t];
else return -1;
}
void EK(int s,int t)
{
int delta=bfs(s,t);//寻找最短增广路的最大流量
while (delta!=-1)
{
ans+=delta;
for (int j=t;j;j=prep[j])
{
e[pree[j]].val-=delta;
e[pree[j]^1].val+=delta;
//链式前向星存边从编号2开始存储可以通过异或1快速取得反向边的编号。
}
delta=bfs(s,t);
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
cnt=1;
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(v,u,0);
add(u,v,w);
//加入正反边
}
EK(s,t);
printf("%d",ans);
return 0;
}
Luogu P3381
假设现在对每一条弧加入一个费用,表示该弧单位流量需要的费用,要求最小费用最大流。
那么这就是费用流问题。
事实上并不难,对EK算法稍作修改,将EK中BFS寻找最短增广路改成SPFA寻找最小费用的增广路即可
#include<cstdio>
#include<queue>
using namespace std;
const int maxn=5005,maxm=50005,inf=0x3f3f3f3f;
struct data
{
int to,next,val,pri;
}e[2*maxm];
int cnt,tot,ans,head[maxn],n,m,s,t,u,v,w,f,cost[maxn],prep[maxn],pree[maxn],flow[maxn];
void add(int u,int v,int w,int f)
{
e[++cnt].to=v;
e[cnt].next=head[u];
e[cnt].val=w;
e[cnt].pri=f;
head[u]=cnt;
}
queue<int> que;
int vis[maxn];
int SPFA(int s,int t)
{
for (int i=1;i<=n;i++)
{
cost[i]=inf;
prep[i]=-1;
pree[i]=0;
flow[i]=inf;
//初始化容易漏
}
cost[s]=0;
que.push(s);
vis[s]=true;
prep[s]=0;pree[s]=0;flow[s]=inf;
while (!que.empty())
{
int now=que.front();
que.pop();
vis[now]=false;
for (int i=head[now];i;i=e[i].next)
{
if (e[i].val>0&&cost[e[i].to]>cost[now]+e[i].pri)
{
cost[e[i].to]=cost[now]+e[i].pri;
flow[e[i].to]=min(flow[now],e[i].val);
prep[e[i].to]=now;
pree[e[i].to]=i;
if (!vis[e[i].to])
{
vis[e[i].to]=true;
que.push(e[i].to);
}
}
}
}
if (prep[t]!=-1) return flow[t];
else return -1;
}
void EK(int s,int t)
{
int delta=SPFA(s,t);
while (delta!=-1)
{
ans+=delta;tot+=delta*cost[t];
for (int j=t;j;j=prep[j])
{
e[pree[j]].val-=delta;
e[pree[j]^1].val+=delta;
}
delta=SPFA(s,t);
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
cnt=1;
for (int i=1;i<=m;i++)
{
scanf("%d%d%d%d",&u,&v,&w,&f);
add(u,v,w,f);
add(v,u,0,-f);//反向边的费用取相反数
}
EK(s,t);
printf("%d %d",ans,tot);
return 0;
}
【Luogu P3376】网络最大流的更多相关文章
- 【luogu P3376 网络最大流】 模板
题目链接:https://www.luogu.org/problemnew/show/P3376 #include <iostream> #include <cstdio> # ...
- 【Luogu】P3376网络最大流模板(Dinic)
最大流模板成为另一个被攻克的模板题. 今天QDC给我讲了一下Dinic,感觉很好懂.于是为了巩固就把这道题A掉了. 核心思想就是不断BFS分层,然后不断DFS找增广路.找不到之后就可以把答案累加输出了 ...
- P3376 网络最大流模板(Dinic + dfs多路增广优化 + 炸点优化 + 当前弧优化)
### P3376 题目链接 ### 这里讲一下三种优化的实现以及正确性. 1.dfs多路增广优化 一般的Dinic算法中是这样的,bfs() 用于标记多条增广路,以至于能一次 bfs() 出多次 d ...
- P3376 【模板】网络最大流(luogu)
P3376 [模板]网络最大流(luogu) 最大流的dinic算法模板(采取了多种优化) 优化 时间 inline+当前弧+炸点+多路增广 174ms no 当前弧 175ms no 炸点 249 ...
- luogu P3376 【模板】网络最大流(no)ek
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...
- Dinic最大流 || Luogu P3376 【模板】网络最大流
题面:[模板]网络最大流 代码: #include<cstring> #include<cstdio> #include<iostream> #define min ...
- P3376 【模板】网络最大流
P3376 [模板]网络最大流 题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点 ...
- P3376 【模板】网络最大流dinic算法
P3376 [模板]网络最大流 题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点 ...
- 『题解』洛谷P3376 【模板】网络最大流
Problem Portal Portal1:Luogu Description 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. Input 第一行包含四个正整数\(N,M,S,T\),分 ...
随机推荐
- centos7将python默认版本升级
想用centos7来写python,但是默认安装的是python2.7(python -v命令可以查看版本信息) 准备升级到python3.5.2 首先安装编译环境 yum -y install gc ...
- angularjs通过ng-bind-html指令和$sce服务绑定html
代码: <!doctype html> <html lang="en"> <head> <meta charset="UTF-8 ...
- 不离开Emacs完成简单程序的编辑编译运行(windows或Linux)
(1)打开Emacs (2)建立一个新的程序文件. 执行 C-x C-f, 然后在屏幕的底部出现minibuffer,光标提示你输入文件名称, 文件名称要带上后缀名,如hello.cpp.回车,然后开 ...
- Unity常用协程功能封装
# 1.前言unity开发过程中,经常用到一些特定的协程功能,比如延时触发.等待触发.重复操作等.unity自带Invoke以及InvokeRepeating方法,但这些方法均采用反射机制,性能消耗, ...
- (乱入)FingerGesture
偶然的机会遇到FingerGesture插件,此插件也有很多方便的功能,比如控制主相机查看模型以及缩放等功能,如Component-FingerGestures-Toolbox-Camera-Orbi ...
- C# leetcode 之 096 不同的二叉搜索树
C# leetcode 之 096 不同的二叉搜索树 题目描述 给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种? 二叉搜索树定义 左子树上所有节点的值小于根节点, 右子树上左右 ...
- 9、pytest -- 集成文档测试
目录 1. 集成doctest模块 1.1. 通过指定文本文件的方式 1.2. 通过编写文档字符串的方式 1.3. 指定额外的选项 2. 失败时继续执行 3. 指定输出的格式 4. 文档测试中使用fi ...
- Flink中接收端反压以及Credit机制 (源码分析)
先上一张图整体了解Flink中的反压 可以看到每个task都会有自己对应的IG(inputgate)对接上游发送过来的数据和RS(resultPatation)对接往下游发送数据, 整个反压机制通 ...
- 学习笔记04IIS
IIS机制:1.能监听端口,获取socket的客户端对象2.获取请求报文,将请求报文变成对象.3.处理请求报文,通过HttpApplication.ProcessRequest方法来处理HttpCon ...
- 使用float设置经典的网站前端结构
float浮动是能使得标签脱离文档流,此处脱离文档流,是指此便签后面的,没有脱离文档流的标签将此标签当作透明,按正常来布局. float脱离文档流,是受到父级范围限制的,在父级范围内脱离文档流,脱离文 ...