Front Push-Relabel Algorithm

接口定义

  • Input:容量数组vector<vector<int>> capacity ,大小为n;源点int source,汇点int sink
  • Output:最大流int maxflow

算法描述

数据结构

  • flow:n*n的二维数组,表示结点间的流量,flow[u][v]非零当且仅当capacity[u][v]非零。
  • excess:n维数组,表示结点的溢出流量。
  • height:n维数组,表示结点的高度。
  • L:除去源点和汇点后,其余结点组成的链表,遍历此链表进行discharge操作。
  • current:n维数组,表示结点u当前考虑推送的相邻结点。

算法步骤

初始化

源点高度设置为n,其余结点必须先尝试推送到所有其他结点,还有溢出的流才能将流返还源点。初始化链表L。遍历源点的所有相邻边,填满这些边的流量,并设置相邻结点的溢流。

// initialize data structure
int n = capacity.size();
vector<vector<int>> flow(n, vector<int>(n, 0));
vector<int> excess(n, 0);
vector<int> height(n, 0);
height[source] = n;
list<int> L;
for (int u = 0; u < n; u++) {
if (u != source && u != sink) {
L.push_back(u);
}
}
vector<int> current(n, 0);
// initialize perflow
for (int v = 0; v < n; v++) {
if (capacity[source][v] > 0) {
flow[source][v] = capacity[source][v];
excess[v] = capacity[source][v];
excess[source] -= capacity[source][v];
}
}

push操作

仅当结点u存在溢流,边(u,v)存在残留容量,且u的高度恰好比v的高度大1时(符合这一条件的边称为许可边),将多余流量尽可能从u推送到v。注意残留容量residual定义为:

  1. (u,v)是流网络的边,即容量非零,则等于剩余容量C[u][v] - F[u][v]
  2. 否则,等于反向流量F[v][u],表示允许将溢流倒回,降低边(v,u)的流量;

因此,除了修改两个结点的溢流外,还需分上面的两种情况修改边的流量。

void push(vector<vector<int>>& C, vector<vector<int>>& F, vector<int>& E, int u, int v) {
int residual = C[u][v] > 0 ? C[u][v] - F[u][v] : F[v][u];
int delta = min(E[u], residual);
E[u] -= delta;
E[v] += delta;
if (C[u][v] > 0) {
F[u][v] += delta;
}
else {
F[v][u] -= delta;
}
}

relabel操作

仅当结点u存在溢流,其不存在许可边。则将u的高度设置为其最低的存在残留容量的相邻结点的高度加1,使得它们之间的边成为许可边。

void relabel(vector<vector<int>>& C, vector<vector<int>>& F, vector<int>& H, int u) {
int min_height = INT_MAX;
for (int v = 0; v < C.size(); v++) {
int residual = C[u][v] > 0 ? C[u][v] - F[u][v] : F[v][u];
if (residual > 0) {
min_height = min(min_height, H[v]);
}
}
H[u] = min_height + 1;
}

discharge操作

反复尝试将结点u的溢流推送出去,直到结点u不存在溢流。使用current数组存储当前u考虑推送的目标,如果目标不可推送(非许可边),则考虑下一个邻接点。如果所有邻接点均尝试过且溢流仍然非零,则relabel,并重新将current指向头部。如果成功推送则不动current

void discharge(vector<vector<int>>& C, vector<vector<int>>& F, vector<int>& E, vector<int>& H, vector<int>& current, int u) {
while (E[u] > 0) {
int v = current[u];
if (v >= C.size()) {
relabel(C, F, H, u);
current[u] = 0;
}
else {
int residual = C[u][v] > 0 ? C[u][v] - F[u][v] : F[v][u];
if (residual > 0 && H[u] == H[v] + 1) {
push(C, F, E, u, v);
}
else {
current[u]++;
}
}
}
}

算法主体

从链表L的头部开始discharge结点,如果将结点的溢流释放后高度发生了变化,则需要重新将结点放到表头并遍历其余结点进行释放。实际上这是为了保证链表中结点u之前的结点不存在溢流(relabel以后可能会将流倒回之前的结点),这样算法结束时链表中所有结点均不存在溢流。

结束时,源点的溢流应该等于最大流的相反数,这是因为源点没有流入只有流出,而流出的流量之和就等于最大流。

int getMaxFlow(vector<vector<int>> capacity, int source, int sink) {
// initialize data structure
int n = capacity.size();
vector<vector<int>> flow(n, vector<int>(n, 0));
vector<int> excess(n, 0);
vector<int> height(n, 0);
height[source] = n;
list<int> L;
for (int u = 0; u < n; u++) {
if (u != source && u != sink) {
L.push_back(u);
}
}
vector<int> current(n, 0);
// initialize perflow
for (int v = 0; v < n; v++) {
if (capacity[source][v] > 0) {
flow[source][v] = capacity[source][v];
excess[v] = capacity[source][v];
excess[source] -= capacity[source][v];
}
}
// relabel to front
auto u = L.begin();
while (u != L.end()) {
int old_height = height[*u];
discharge(capacity, flow, excess, height, current, *u);
if (height[*u] > old_height) {
int tmp = *u;
L.erase(u);
L.push_front(tmp);
u = L.begin();
}
u++;
}
// compute max flow
return -excess[source];
}

优化写法

可以简化residual的计算,允许数组flow存在负值,用来表示反向流量,这样残留容量residual可以统一成一个表达式:residual = C[u][v] - F[u][v]。相应的需要修改push操作,将ifelse去掉,增加当前方向的流量的同时,将反向流量减少,从而同时更新了反向边。

最大流-前置push-relabel算法实现的更多相关文章

  1. [洛谷P3376题解]网络流(最大流)的实现算法讲解与代码

    [洛谷P3376题解]网络流(最大流)的实现算法讲解与代码 更坏的阅读体验 定义 对于给定的一个网络,有向图中每个的边权表示可以通过的最大流量.假设出发点S水流无限大,求水流到终点T后的最大流量. 起 ...

  2. 最大流EK和Dinic算法

    最大流EK和Dinic算法 EK算法 最朴素的求最大流的算法. 做法:不停的寻找增广路,直到找不到为止 代码如下: @Frosero #include <cstdio> #include ...

  3. POJ 1273 - Drainage Ditches - [最大流模板题] - [EK算法模板][Dinic算法模板 - 邻接表型]

    题目链接:http://poj.org/problem?id=1273 Time Limit: 1000MS Memory Limit: 10000K Description Every time i ...

  4. hdoj 3488 Tour 【最小费用最大流】【KM算法】

    Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submi ...

  5. HDOJ-3416(最大流+最短路+ISAP算法+向前星dijikstra算法+如何判断一条边是否在最短路中)

    Marriage Match IV HDOJ-3416 这题的题意就是要找两点之间最短路的路径个数,而且边不能重复. 最大流和最短路的结合.首先正向和反向建图,再跑两遍dijikstra.到这里就求出 ...

  6. Power Network (最大流增广路算法模板题)

    Time Limit: 2000MS   Memory Limit: 32768K Total Submissions: 20754   Accepted: 10872 Description A p ...

  7. hdu1532 (最大流入门,EK算法)

    看着这个博客 然后敲了hdu1532这个入门题,算是对最大流有点理解了 #include <stdio.h> #include <string.h> #include < ...

  8. 限流之令牌桶算法——RateLimiter官方文档

    原文链接 作者:Dimitris Andreou  译者:魏嘉鹏 校对:方腾飞 RateLimiter 从概念上来讲,速率限制器会在可配置的速率下分配许可证.如果必要的话,每个acquire() 会阻 ...

  9. hdu3572Task Schedule 最大流,判断满流 优化的SAP算法

    PS:多校联赛的题目质量还是挺高的.建图不会啊,看了题解才会的. 参考博客:http://blog.csdn.net/luyuncheng/article/details/7944417 看了上面博客 ...

随机推荐

  1. Docker+Nginx使用流程(笔记)

    Docker+Nginx使用流程 本教程依据个人理解并经过实际验证为正确,特此记录下来,权当笔记. 注:基于linux操作系统 # uname -r 查看你当前的内核版本 # yum -y insta ...

  2. 如何修改Docker已运行实例的端口映射

    如何修改Docker已运行实例的端口映射 Docker的端口映射,往往出现在两个阶段需要处理: 1.是在docker启动前就已经确定好,哪个docker实例映射哪个端口(往往这个情况比较,需要提前做规 ...

  3. pdf文件内容查看器 -- 采用wpf开发

    前言 pdf是一种应用非常广的版式文档格式,已成为事实上的国际标准.关于pdf格式的文章汗牛充栋,本文也是关于pdf格式的文章,但是本文不是纸上谈兵:本人这几周一直研究pdf格式内容,不但对pfd格式 ...

  4. python列表的 + 、* 、in 、 not in 、 len() 、 max() 、 min()

    + 列表拼接 first_list = [1,2,3] + ['a',5] # + 将列表拼接 print(first_list) # [1, 2, 3, 'a', 5] *  列表与数字n相乘 : ...

  5. React Hooks 一步到位

    useState 用来声明状态变量. import React, { useState } from 'react'; // ... const [ count , setCount ] = useS ...

  6. idea 2019.3 最新版破解教程

    背景 最近,idea又被整治了,所以一大批激活码都失效了.我之前已经有2018版的永久激活了,所以非常淡定~,也没打算升级版本.但是,最近发现周围的人都在讨论这个问题.于是,我也找到了2019.3最新 ...

  7. scrapy selector选择器

    这部分内容属于补充内容 1.xpath() 2.css() 3.正则表达式 # 多个值,列表 response.xpath('//a/text()').re('(.*?):\s(.*)') # 取第一 ...

  8. Java入门 - 语言基础 - 07.修饰符

    原文地址:http://www.work100.net/training/java-modifier-type.html 更多教程:光束云 - 免费课程 修饰符 序号 文内章节 视频 1 概述 2 访 ...

  9. 异数OS 织梦师-水母(一)--消息队列篇

    异数OS 织梦师-水母(一)–消息队列篇 本文来自异数OS社区 github: https://github.com/yds086/HereticOS 异数OS社区QQ群: 652455784 异数O ...

  10. chrome最耐看的主题

    google chrome最耐看的主题James White大家可以尝试一下