最小费用流模板(zkw与spfa)
“zkw” 费用流算法在哪些图上慢(摘自https://www.cnblogs.com/ECJTUACM-873284962/p/7744943.html)
实践中, 上面的这个算法非常奇怪. 在某一些图上, 算法速度非常快,
另一些图上却比纯 SPFA 增广的算法慢. 不少同学经过实测总结的结果是稠密图上比较快,
稀疏图上比较慢, 但也不尽然. 这里我从理论上分析一下, 究竟这个算法用于哪些图可以得到理想的效果.
先分析算法的增广流程. 和 SPFA 直接算法相比, 由于同属于沿最短路增广的算法,
实际进行的增流操作并没有太多的区别, 每次的增流路径也大同小异. 因此不考虑多路增广时,
增广次数应该基本相同. 运行时间上主要的差异应当在于如何寻找增流路径的部分.
那么 zkw 算法的优势在于哪里呢?
与 SPFA 相比, KM 的重标号方式明显在速度上占优, 每次只是一个对边的扫描操作而已.
而 SPFA 需要维护较为复杂的标号和队列操作, 同时为了修正标号, 需要不止一次地访问某些节点, 速度会慢不少.
另外, 在 zkw 算法中, 增广是多路进行的, 同时可能在一次重标号后进行多次增广.
这个特点可以在许多路径都费用相同的时候派上用场, 进一步减少了重标号的时间耗费.
下面想一想 zkw 算法的劣势, 也就是 KM 重标号方式存在的问题.
KM 重标号的主要问题就是, 不保证经过一次重标号之后能够存在增广路.
最差情况下, 一次只能在零权网络中增加一条边而已. 这时算法就会反复重标号,
反复尝试增广而次次不能增广, 陷入弄巧成拙的境地.
接下来要说什么, 大家可能已经猜到了. 对于最终流量较大, 而费用取值范围不大的图,
或者是增广路径比较短的图 (如二分图), zkw 算法都会比较快. 原因是充分发挥优势.
比如流多说明可以同一费用反复增广, 费用窄说明不用改太多距离标号就会有新增广路,
增广路径短可以显著改善最坏情况, 因为即使每次就只增加一条边也可以很快凑成最短路.
如果恰恰相反, 流量不大, 费用不小, 增广路还较长, 就不适合 zkw 算法了.
费用流板题:luoguP3381 【模板】最小费用最大流
zkw版/板:
#include <bits/stdc++.h>
using namespace std;
void read(int &num)
{
char ch; bool flag=0;
while(!isdigit(ch=getchar()))if(ch=='-')flag=!flag;
for(num=0;isdigit(ch);num=num*10+ch-'0',ch=getchar());
if(flag)num=-num;
}
const int MAXN = 5005;
const int MAXM = 50005;
const int inf = 1e9;
int n, m, S, T, Ans;
int cnt = 1, fir[MAXN], nxt[MAXM*2], to[MAXM*2], c[MAXM*2], w[MAXM*2];
int dis[MAXN];
bool vis[MAXN];
void Add(int u, int v, int cc, int wt)
{
to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt; c[cnt] = cc; w[cnt] = wt;
}
int Aug(int u, int flow)
{
if(u == T) { return flow; }
int used = 0, delta = 0;
vis[u] = true;
for(int i = fir[u]; i; i = nxt[i])
if(!vis[to[i]] && c[i] && dis[u] == dis[to[i]] + w[i])
{
delta = Aug(to[i], min(c[i], flow-used));
c[i] -= delta, c[i^1] += delta, used += delta;
Ans += delta * w[i];
if(used == flow) break;
}
return used;
}
bool Update()
{
int tmp = inf;
for(int i = 1; i <= n; i++) if(vis[i])
for(int j = fir[i]; j; j = nxt[j])
if(!vis[to[j]] && c[j]) tmp = min(tmp, dis[to[j]]-dis[i]+w[j]);
if(tmp == inf) return false;
for(int i = 1; i <= n; i++) if(vis[i]) dis[i] += tmp;
return true;
}
int Cost_flow()
{
int flow = 0, tmp = 0;
do {
do { flow += tmp; memset(vis, 0, sizeof vis); }while(tmp=Aug(S, inf));
}while(Update());
return flow;
}
int main ()
{
int u, v, x, y;
read(n), read(m), read(S), read(T);
for(int i = 1; i <= m; i++)
{
read(u), read(v), read(x), read(y);
Add(u, v, x, y);
Add(v, u, 0, -y);
}
int Max_flow = Cost_flow();
printf("%d %d\n", Max_flow, Ans);
}
spfa版:
#include <bits/stdc++.h>
using namespace std;
void read(int &num)
{
char ch; bool flag=0;
while(!isdigit(ch=getchar()))if(ch=='-')flag=!flag;
for(num=0;isdigit(ch);num=num*10+ch-'0',ch=getchar());
if(flag)num=-num;
}
const int MAXN = 5005;
const int MAXM = 50005;
const int inf = 1e9;
int n, m, S, T, Ans;
int cnt = 1, fir[MAXN], nxt[MAXM*2], to[MAXM*2], c[MAXM*2], w[MAXM*2];
int dis[MAXN];
bool vis[MAXN];
void Add(int u, int v, int cc, int wt)
{
to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt; c[cnt] = cc; w[cnt] = wt;
}
bool spfa(int s, int t)
{
memset(vis, 0, sizeof vis);
for(int i = 0; i <= n; i++) dis[i] = inf;
dis[t] = 0; vis[t] = true;
deque<int> Q; Q.push_back(t);
while(!Q.empty())
{
int u = Q.front(); Q.pop_front();
for(int i = fir[u]; i; i = nxt[i])
if(c[i^1] && dis[to[i]] > dis[u] - w[i])
{
dis[to[i]] = dis[u] - w[i];
if(!vis[to[i]])
{
vis[to[i]] = true;
if(!Q.empty() && dis[to[i]] < dis[Q.front()]) Q.push_front(to[i]);
else Q.push_back(to[i]);
}
}
vis[u] = 0;
}
return dis[S] < inf;
}
int Aug(int u, int flow)
{
if(u == T) { vis[T] = true; return flow; }
int used = 0, delta = 0;
vis[u] = true;
for(int i = fir[u]; i; i = nxt[i])
if(!vis[to[i]] && c[i] && dis[u] == dis[to[i]] + w[i])
{
delta = Aug(to[i], min(c[i], flow-used));
Ans += delta * w[i], c[i] -= delta, c[i^1] += delta, used += delta;
if(used == flow) break;
}
return used;
}
int Cost_flow()
{
int flow = 0;
while(spfa(S, T))
{
vis[T] = 1;
while(vis[T])
{
memset(vis, 0, sizeof vis);
flow += Aug(S, inf);
}
}
return flow;
}
int main ()
{
int u, v, x, y;
read(n), read(m), read(S), read(T);
for(int i = 1; i <= m; i++)
{
read(u), read(v), read(x), read(y);
Add(u, v, x, y);
Add(v, u, 0, -y);
}
int Max_flow = Cost_flow();
printf("%d %d\n", Max_flow, Ans);
}
最小费用流模板(zkw与spfa)的更多相关文章
- [转]从入门到精通: 最小费用流的“zkw算法”
>>>> 原文地址:最小费用流的“zkw算法” <<<< 1. 网络流的一些基本概念 很多同学建立过网络流模型做题目, 也学过了各种算法, 但是对于基本 ...
- POJ 3068 运送危险化学品 最小费用流 模板题
"Shortest" pair of paths Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 1215 ...
- LG P2285 [模板]负环(spfa判负环)
题目描述 寻找一个从顶点1所能到达的负环,负环定义为:一个边权之和为负的环. 输入格式 第一行一个正整数T表示数据组数,对于每组数据: 第一行两个正整数N M,表示图有N个顶点,M条边 接下来M行,每 ...
- HYSBZ 1061 志愿者招募 【最小费用流】【差分】【最小费用流模板】
#include<stdio.h> #include<queue> #define MAXN 1003 #define MAXM 10002*4 #define INF 100 ...
- 洛谷P3385 [模板]负环 [SPFA]
题目传送门 题目描述 暴力枚举/SPFA/Bellman-ford/奇怪的贪心/超神搜索 输入输出格式 输入格式: 第一行一个正整数T表示数据组数,对于每组数据: 第一行两个正整数N M,表示图有N个 ...
- [模板] zkw线段树
zkw线段树 code1简单版本 code2差分版本(暂无) code1:(有注释) //By Menteur_Hxy #include<cstdio> #include<iostr ...
- 【模板】裸SPFA
SPFA可以处理带负边权的图,可以判负环,然而SPFA容易被卡,即使加了各种优化. 队列优化的贝尔福德曼:裸SPFA //SPFA #include<bits/stdc++.h> usin ...
- 网络流之最大流与最小费用流入门&&模板
理解处 刷题处 模板处 最大流模板 处理重边的+(优化) #include<bits/stdc++.h> using namespace std; ; const int INF = 0x ...
- POJ 2449Remmarguts' Date K短路模板 SPFA+A*
K短路模板,A*+SPFA求K短路.A*中h的求法为在反图中做SPFA,求出到T点的最短路,极为估价函数h(这里不再是估价,而是准确值),然后跑A*,从S点开始(此时为最短路),然后把与S点能达到的点 ...
随机推荐
- Mybatis中实体类属性与数据库列表间映射方法介绍
这篇文章主要介绍了Mybatis中实体类属性与数据列表间映射方法介绍,一共四种方法方法,供大家参考. Mybatis不像Hibernate中那么自动化,通过@Co ...
- 解决Jupyter notebook安装后不自动跳转网页的方法
在安装完Jupyter notebook后,有童鞋说出现了各种不友好的问题,鉴于此情况,个人先随手写出以下三种情况,并给出解决方法: 题外建议:请使用谷歌浏览器为默认浏览器 一.对于弹不出浏览器的解决 ...
- gensim快速上手教程
1 gensim是什么? gensim是一个Python常用的的自然语言处理开发包, 主要用于词向量训练和加载词向量,以下解释其正确使用姿势. 2 正确使用姿势 from gensim. ...
- .NET/C# 检测电脑上安装的 .NET Framework 的版本
原文:.NET/C# 检测电脑上安装的 .NET Framework 的版本 如果你希望知道某台计算机上安装了哪些版本的 .NET Framework,那么正好本文可以帮助你解决问题. 本文内容 如何 ...
- django路由的反向解析
什么是路由的反向解析 我们的路由都是一个匹配关系,对应一个处理的视图函数, 如果我们的匹配关系发生了变化,那么与之对应的访问地址(可能前端直接url链接, 也可能是后端的redrict跳转)都需要跟着 ...
- centOS学习part6:安装oracle 11g
0 大家好.上一章(http://www.cnblogs.com/souvenir/p/3881484.html)我们对oracle在centOS下的安装进行了各项环境准备,本章我们将正式进行oral ...
- nginx mirror/post_action+gor实现https流量复制
关于gor: 参考: https://www.cnblogs.com/jinjiangongzuoshi/p/11773070.html https://github.com/buger/gorepl ...
- RedisCluster的rename机制失败报错,解决又是数据倾斜问题
需求说明:spring session中的用户session更新是更新key的名字,所以对于key的操作时需要用newkey 替换oldkey value值只允许存在一个,这里用到rename就很合适 ...
- mysql 模糊查询like小结
以不完整的条件进行查询 因为条件是模糊的 所以叫模糊查询,可以对有相同信息的数据快速归类 . like 运算符:可以很好的通过%和-两种通配符对数据进行筛选查询 %(所有)放在条件前中后.可查询包含 ...
- Python——字符串增加颜色
给显示字符添加颜色: salary=int(input('\033[31;1m请输入你的工资:\033[0m')) ('\033[;1m请输入你的工资:\033[0m') 3x是给字符串改变颜色 31 ...