码迷,mamicode.com
首页 > 其他好文 > 详细

Maximum Flow

时间:2020-03-04 23:05:40      阅读:69      评论:0      收藏:0      [点我收藏+]

标签:没有   href   resize   arp   大小   最大   基本   邻接矩阵   图论   

本文参考以下文章

Flow Networks基本性质

在图论中,网络流被定义为一个有向图,其中包含一个起点Source和一个终点Target,以及几条连接各顶点的边。每条边都有各自的容量Capacity,这是边所能允许的最大流量

网络流中的流量\(f\)应满足如下条件

  • 从节点\(x\)流向节点\(y\)的流量,不能比\(edge(x,y)\)capacity还大,\(f(x,y)≤c(x,y)\)
  • 若定义 从节点\(x\)流向节点\(y\)的的流量有5单位,\(f(x,y)=5\),则 从节点\(y\)流向节点\(x\)的流量有-5单位,\(f(y,x)=-5\)
  • 对图中除了Source和Target以外的结点,所有输入的流量之和要等于所有输出的流量之和
    • 也就是流量不会无故增加或无故减少,可视为一种能量守恒
    • 以下图为例,流入节点A的流量为6,流出的流量也是6,对C、D也是

技术图片

最大流:网络允许从源Source流向终点Target的最大流量

下面介绍Ford-Fulkerson Algorithm(若使用BFS,则又称为Edmonds-Karp Algorithm)来解决此问题

Ford-Fulkerson Algorithm

Ford-Fulkerson Algorithm需要两个辅助工具

  1. Residual Networks(残差网络)
  2. Augmenting Paths(增广路径)

Residual Networks

残差网络表示图中每条边剩余可允许通过的流量构成的图,以下图为例

技术图片

若在Path:S-A-C-D-T上的所有边都有6单位的流量,那么这些边,\(edge(S,A)\)\(edge(A,C)\)\(edge(C,D)\)\(edge(D,T)\)的剩余容量都应该减6。例如,\(edge(S,A)\)只能容纳3单位的流量,\(edge(C,D)\)只能容纳1单位的流量

\(edge(x,y)\)上有\(f(x,y)\)单位的流量流过,则\(edge(x,y)\)上的residual capacity定义为:

  • \(c_f(x,y)=c(x,y)-f(x,y)\)
    • \(c(x,y)\)为原始edge(x,y)的容量
    • \(f(x,y)\)表示目前edge(x,y)已有多少流量
    • \(c_f(x,y)\)表示edge(x,y)还能容纳多少流量

Residual Networks也是一个有向图,其中:

  • 顶点集与原有向图完全相同
  • 边的容量被residual capacity取代,如下图所示

技术图片

最关键的是,若\(edge(A,C)\)上有6单位的流量流过\(f(A,C)=6\),那么在其Residual Networks上,会相应产生出一条顶点C指向顶点A的边\(edge(C,A)\),并具有6单位的residual capacity\(c_f(C,A)=6\)

这样做有什么意义?可以用如果想要重新配置流量方向来理解

举例来说,假设现在恢复到初始状态(没有任何流量流过),现在有2单位的流量经过Path:S-C-A-B-T,但是由于并不存在从顶点C指向顶点A的\(edge(C,A)\),因此\(c(C,A)=0\)。假设有6单位的流量从顶点A流向顶点C(如上图所示),那么现在就可以从\(edge(A,C)\)上把2单位的流量收回,从而分配到\(edge(A,B)\)上,而\(edge(A,C)\)上,就只剩下4单位的流量,最后结果如下图左所示,此时的Residual Networks如下图右所示

技术图片

下图是从网上找到的另一个例子

技术图片

Augmenting Paths

Residual Networks里,所有能够从源Source走到终Target的路径,也就是所有能够增加流量的路径,就称为Augmenting Paths(增广路径)

技术图片

以上图为例,Augmenting Paths有很多种可能,例如

  • Path:S-A-B-T,1~3单位的流量
    • 因为在该路径中,所有edge中最小的capacity为\(c(S,A)=c(A,B)=3\),因此可以容许流量大小为1~3
  • Path:S-C-B-D-T,1~2单位的流量
    • 因为在该路径中,所有edge中最小的capacity为\(c(B,D)=c(D,T)=2\),因此可以容许的流量大小为1~2

综上

  • 若要看当前流入Target的总流量,要在下图左,edge上标示flow/capacity的图上找
    • 下图左流入终点Target的flow为8单位
  • 若要找还能增加多少流量,也就是找Augmenting Paths,需要在Residual Networks上找,如下图右所示
    • 若在Path:S-A-B-T、Path:S-A-C-D-T、Path:S-C-B-T流入不超过该路径上最低residual capacity的flow, 都是Augmenting Paths

技术图片

讲完上面两个概念,下面讲解Ford-Fulkerson Algorithm算法

  • Residual Networks上寻找Augmenting Paths
    • BFS()寻找,确保每次找到的Augmenting Paths一定经过最少的edge
    • 找到Augmenting Paths上最小的residual capacity,将其加入总flow
    • 再以最小的residual capacity更新Residual Networks上edge的residual capacity
  • 重复上述步骤,直到再也没有Augmenting Paths为止

技术图片

以上图为例,寻找Maximum Flow的步骤如下

  • 开始时用flow = 0初始化residual Networks

技术图片

  • 在图中,以bfs()找到从ST且edge最少的Path:S-A-B-T
    • bfs()找到的可能有三条最短Path,这里就以S-A-B-T为例

技术图片

  • 观察Path:S-A-B-T上的edge,发现\(edge(A,B)\)具有最小的residual capacity \(c_f(A,B)=3\),所以update:总flow增加3
  • 更新edge的residual capacity
    • \(c_f(S,A)=c(S,A)-f(S,A)=9-3=6\)
    • \(c_f(A,S)=c(A,S)-f(A,S)=0+3=3\)
    • \(c_f(A,B)=c(A,B)-f(A,B)=3-3=0\)
    • \(c_f(B,A)=c(B,A)-f(B,A)=0+3=3\)
    • \(c_f(B,T)=c(B,T)-f(B,T)=9-3=6\)
    • \(c_f(T,B)=c(T,B)-f(T,B)=0+3=3\)

技术图片

  • 在途中,以bfs()找到从S*到T且edge最少的Path:S-C-D-T

技术图片

  • 观察Path:S-C-D-T上的edge,发现\(edge(C,D)\)具有最小的residual capacity \(c_f(C,D)=7\),所以update:总flow增加7

  • 更新edge的residual capacity

    • \(c_f(S,C)=c(S,C)-f(S,C)=9-7=2\)
    • \(c_f(C,S)=c(C,S)-f(C,S)=0+7=7\)
    • \(c_f(C,D)=c(C,D)-f(C,D)=7-7=0\)
    • \(c_f(D,C)=c(D,C)-f(D,C)=0+7=7\)
    • \(c_f(D,T)=c(D,T)-f(D,T)=8-7=1\)
    • \(c_f(T,D)=c(D,T)-f(T,D)=0+7=7\)

技术图片

接着重复上述步骤:更新Residual Networks,寻找Augmenting Paths

  • 找到Path:S-C-B-T

技术图片

  • 更新Residual Networks

技术图片

  • 找到Path:S-A-C-B-T

技术图片

  • 更新Residual Networks

技术图片

  • 找到Path:S-A-C-B-D-T

技术图片

  • 更新Residual Networks

技术图片

  • 找到Maximum Flow=17

技术图片

完整代码如下

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

class Graph {
private:
    int num_vertex; //顶点
    vector<vector<int>> map; // 邻接矩阵
public:
    Graph():num_vertex(0){};
    Graph(int n);
    void AddEdge(int from, int to, int capacity);
    void FordFulkerson(int s, int t);
    bool BfsFindExistingPath(vector<vector<int>> graph, int* predecessor, int s, int t);
    int MinCapacity(vector<vector<int>> graph, int* predecessor, int t);
};

Graph::Graph(int n):num_vertex(n) {
    map.resize(num_vertex);
    for (int i = 0; i < num_vertex; i++)
        map[i].resize(num_vertex);
}

bool Graph::BfsFindExistingPath(vector<vector<int>> graph, int* predecessor, int s, int t) {
    int visited[num_vertex];
    for (int i = 0; i < num_vertex; i++) {
        visited[i] = 0; // 0 表示没有访问过
        predecessor[i] = -1;
    }

    queue<int> queue;
    queue.push(s);
    visited[s] = 1; // 1 表示访问过
    while (!queue.empty()) {
        int vertex = queue.front(); queue.pop();
        for (int j = 0; j < num_vertex; j++) {
            if (graph[vertex][j] != 0 && visited[j] == 0) {
                queue.push(j);
                visited[j] = 1;
                predecessor[j] = vertex;
            }
        }
    }
    return (visited[t] == 1); // 若t被访问过,表示有path从s到t
}

int Graph::MinCapacity(vector<vector<int>> graph, int* predecessor, int t) {
    int min = 0x3f3f3f; // 确保min会更新,假设graph上的capacity都小于0x3f3f3f
    
    // 用predecessor[idx]和idx表示一条edge
    // 找到 从s到t 的path中,capacity最小的值,存入min
    for (int idx = t; predecessor[idx] != -1; idx = predecessor[idx])
        if (graph[predecessor[idx]][idx] != 0 && graph[predecessor[idx]][idx] < min)
            min = graph[predecessor[idx]][idx];
    return min;
}

void Graph::FordFulkerson(int s, int t) {
    vector<vector<int>> graphResidual(map);
    int maxflow = 0;
    int predecessor[num_vertex];

    // bfs find augmeting path
    while (BfsFindExistingPath(graphResidual, predecessor, s, t)) {
        int min_capacity = MinCapacity(graphResidual, predecessor, t);
        maxflow = maxflow + min_capacity;
        for (int y = t; y != s; y= predecessor[y]) {
            // update residual graph
            int x = predecessor[y];
            graphResidual[x][y] -= min_capacity;
            graphResidual[y][x] += min_capacity;
        }
    }
    cout << "Maximum Flow: " << maxflow << endl;
}

void Graph::AddEdge(int from, int to, int capacity) {
    map[from][to] = capacity;
}

int main() {
    Graph g(6);
    g.AddEdge(0, 1, 9);g.AddEdge(0, 3, 9);
    g.AddEdge(1, 2, 3);g.AddEdge(1, 3, 8);
    g.AddEdge(2, 4, 2);g.AddEdge(2, 5, 9);
    g.AddEdge(3, 2, 7);g.AddEdge(3, 4, 7);
    g.AddEdge(4, 2, 4);g.AddEdge(4, 5, 8);

    g.FordFulkerson(0, 5); // 指定source为0,target为5
    return 0;
}

Maximum Flow

标签:没有   href   resize   arp   大小   最大   基本   邻接矩阵   图论   

原文地址:https://www.cnblogs.com/mathor/p/12416573.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!