zoukankan      html  css  js  c++  java
  • graph | Max flow

    最大流算法,解决的是从一个起点到一个终点,通过任何条路径能够得到的最大流量。

    有个Edmond-Karp算法:

    1. BFS找到一条增广路径;算出这条路径的最小流量(所有边的最小值)increase;

    2. 然后更新路径上的权重(流量),正向边加上increase,反向边减去increase;

    3. 重复1,直到没有增广路径;

    可以证明的是在使用最短路增广时增广过程不超过V*E次,每次BFS的时间都是O(E),所以Edmonds-Karp的时间复杂度就是O(V*E^2)。

    图的BFS和DFS的时间复杂度都是O(n+e),这里指用邻接表的方式。每次出栈或者出队列,都要扫一遍该点的所有边,所有点的边集加起来就是O(e)了。

    至于为什么要用反向边,这里讲得挺清楚;

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #include <limits.h>
     5 #include <vector>
     6 using namespace std;
     7 
     8 class Maxflow {
     9     public:
    10 
    11         Maxflow() {}
    12         ~Maxflow() {
    13             if (pre) delete[] pre;
    14             if (flow) delete[] flow;
    15             if (weight) {
    16                 for (int i = 0; i < vertices; ++i) {
    17                     delete[] weight[i];
    18                 }
    19                 delete[] weight;
    20             }
    21         }
    22         void readGraph(string filename) {
    23             freopen(filename.c_str(), "r", stdin);
    24             int edges;
    25             scanf("%d %d", &vertices, &edges);
    26             pre = new int[vertices];
    27             flow = new int[vertices];
    28             memset(flow, 0, vertices * sizeof(int));
    29             weight = new int*[vertices];
    30             for (int i = 0; i < vertices; ++i) {
    31                 weight[i] = new int[vertices];
    32                 memset(weight[i], 0, vertices * sizeof(int));
    33             }
    34 
    35             for (int i = 0; i < edges; ++i) {
    36                 int v1, v2, w;
    37                 scanf("%d %d %d", &v1, &v2, &w);
    38                 weight[v1 - 1][v2 - 1] = w;
    39             }
    40         }
    41 
    42         int maxFlow() {
    43             int start = 0, end = vertices - 1;
    44             int max = 0;
    45             int increase = 0;
    46             while ((increase = bfs(start, end)) != 0) {
    47                 int p = end;
    48                 while (p != start) {
    49                     int b = pre[p];
    50                     weight[b][p] -= increase;
    51                     weight[p][b] += increase;
    52                     p = b;
    53                 }
    54                 max += increase;
    55             }
    56             return max;
    57         }
    58     private:
    59         int bfs(int start, int end) {
    60             memset(pre, -1, vertices * sizeof(int));
    61             vector<vector<int> > layers(2);
    62             int cur = 0, next = 1;
    63             layers[cur].push_back(start);
    64             flow[start] = INT_MAX;
    65 
    66             while (!layers[cur].empty()) {
    67                 layers[next].clear();
    68                 for (int i = 0; i < layers[cur].size(); ++i) {
    69                     int v1 = layers[cur][i];
    70                     for (int v2 = 0; v2 < vertices; ++v2) {
    71                         if (weight[v1][v2] <= 0 || pre[v2] != -1) continue;
    72                         pre[v2] = v1;
    73                         layers[next].push_back(v2);
    74                         flow[v2] = min(flow[v1], weight[v1][v2]);
    75                         if (v2 == end) return flow[v2];
    76                     }
    77                 }
    78 
    79                 cur = !cur;
    80                 next = !next;
    81             }
    82             return 0;
    83         }
    84         int* pre;
    85         int** weight;
    86         int* flow;
    87         int vertices;
    88 };
    89 
    90 int main() {
    91     Maxflow maxflow;
    92     maxflow.readGraph("input.txt");
    93     cout<< maxflow.maxFlow() << endl;
    94     return 0;
    95 }

    sample input:

    1 4 5
    2 1 2 40
    3 1 4 20
    4 2 4 20
    5 2 3 30
    6 3 4 10
  • 相关阅读:
    reference and value type
    搭建基于虚拟机的Windows内核模式调式环境
    C#即时编译器技术测试
    记事本终结者
    实现C#即时编译器
    参数修饰符 params、 out、ref
    重定向Console输出到文本框
    自动属性,对象初始化器,集合初始化器和lambda表达式
    手工搭建32位汇编语言程序开发环境
    匿名方法 Anonymouse Method
  • 原文地址:https://www.cnblogs.com/linyx/p/3989369.html
Copyright © 2011-2022 走看看