zoukankan      html  css  js  c++  java
  • 手撕FordFulkerson algorithm 学一半的笔记

    我明白了,
    余量网络 名如其名
    比如你f/c=3/5
    那么正边2,reverse edge3,加起来是5

    在这个你建的新图上找s到t的路径
    然后path的最小边权叫delta

    给流图的对应path的每条边e都加流 delta,或者 反边减delta (反边的情况)
    得到新的流,重复
    直到余量网络没有s到t的路径
    (最大流-最小割定理也行)

    求最小费用流
    找个最大流,
    然后

    建立个新图
    比如这条边的性质 容量,代价= 6,3,跑着2的流
    那么正向边标4,3
    反向标 2,-3
    新图上找 负环(负环的代价和为负)
    然后min{a_1}
    流加上这个
    流调整了
    重复
    直到新图上找不到 负环(负环的代价和为负)

    不断调整f得到最大流
    我吐了都,要想手撕个算法首先还得理解一些定义

    我找了个课件边看边学

    https://www.cs.princeton.edu/~wayne/kleinberg-tardos/pdf/07NetworkFlowI.pdf

    定义大概就这些

    image-20200821230139062

    Def. The bottleneck capacity of an augmenting path P is the minimum residual capacity of any edge in P

    伪代码

    image-20200821230002386

    其中,AUGMENT()如下

    image-20200821230032530

    自己做slide里的quiz



    搬运别人的代码

    // Copyright srcmake 2018.
    // C++ Example Ford Fulkerson Algorithm
    
    /* Ford Fulkerson Algorithm:
        // 0. Initialize an adjacency matrix to represent our graph.
        // 1. Create the residual graph. (Same as the original graph.)
        // 2. Create an default parent vector for BFS to store the augmenting path. 
        // 3. Keep calling BFS to check for an augmenting path (from the source to the sink...
            // 4. Find the max flow through the path we found.
            // 5. Update the residual capacities of the edges and reverse edges. 
            // 6. Add this path's flow to our total max flow so far.
    */
    
    // The example graph: https://www.srcmake.com/uploads/5/3/9/0/5390645/maxflow_1_orig.jpg
    
    #include <iostream>
    #include <vector>
    #include <queue>
    
    using namespace std;
    
    //////////////////////////////////////////////////////////////////////////////////////////////
    // See the picture here: https://www.srcmake.com/uploads/5/3/9/0/5390645/adjmatrix_1_orig.jpg
    vector< vector<int> > FormAdjMatrix()
        {
        // Our adjacency list.
        vector< vector<int> > adjMatrix;
        
        const int n = 6;
        
        // Initialize our matrix to all 0s.
        for(int i = 0; i < n; i++)
            {
            vector<int> row;
            adjMatrix.push_back(row);
            for(int j = 0; j < n; j++)
                {
                adjMatrix[i].push_back(0);
                }
            }
        
        // First number is the vertex, second is the edge capacity.
        adjMatrix[0][1] = 15;
        adjMatrix[0][2] = 12;
        adjMatrix[1][2] = 9;
        adjMatrix[1][3] = 11;
        adjMatrix[2][1] = 5;
        adjMatrix[2][4] = 13;
        adjMatrix[3][2] = 9;
        adjMatrix[3][5] = 25;
        adjMatrix[4][3] = 8;
        adjMatrix[4][5] = 6;
        
        // Our graph is now represented as an adjacency list. 
        return adjMatrix;
        }
    //////////////////////////////////////////////////////////////////////////////////////////////
    
    
    //////////////////////////////////////////////////////////////////////////////////////////////
    // A special BFS version that returns true if there's a path from source to sink.
    bool BFS(vector< vector<int> > &resAdjMatrix, int &source, int &sink, vector<int> &parent)
        {
        // Create an array for all nodes we visited. Initialized to false.
        int n = resAdjMatrix.size();
        bool visited[n] = { false };
            
        // Create a queue to check each node.
        queue<int> q;
        
        // Push our source into the queue and mark it as visited. It has no parent.
        q.push(source);
        visited[source] = true;
        parent[source] = -1;
            
        // Keep visiting vertices.
        while(q.empty() == false)
            {
            int u = q.front();
            q.pop();
            
            // Check all of u's friends.
            for(int i = 0; i < n; i++)
                {
                int v = i;
                int capacity = resAdjMatrix[u][v];
                
                // We find a neighbor that hasn't been visited, and the capacity is bigger than 0.
                if(visited[v] == false && capacity > 0)
                    {
                    // Push the neighbor onto the queue, mark it's parent, and mark it as visited.
                    q.push(v);
                    parent[v] = u;
                    visited[v] = true;
                    }
                }
            }
            
        // If the sink got visited, then we found a path to it. 
        if(visited[sink] == true) 
            { return true; }
            
        return false;
        }
    //////////////////////////////////////////////////////////////////////////////////////////////
    
    
    //////////////////////////////////////////////////////////////////////////////////////////////
    // Use the Ford Fulkerson algorithm. Return the max flow.
    int FordFulkerson(vector< vector<int> > &adjMatrix, int &source, int &sink)
        {
        int maxflow = 0;
        
        // 1. Create the residual graph. (Same as the original graph.)
        vector< vector<int> > resAdjMatrix;
        int n = adjMatrix.size();
        for(int i = 0; i < n; i++)
            {
            vector<int> row;
            resAdjMatrix.push_back(row);
            for(int j = 0; j < adjMatrix[i].size(); j++)
                {
                resAdjMatrix[i].push_back(adjMatrix[i][j]);
                }
            }
        
        // 2. Create an empty parent array for BFS to store the augmenting path. 
        vector<int> parent;
        for(int i = 0; i < n; i++)
            {
            parent.push_back(-1);
            }
        
        // 3. Keep calling BFS to check for an augmenting path (from the source to the sink...
        while(BFS(resAdjMatrix, source, sink, parent) == true)
            {
            // 4. Find the max flow through the path we just found.
            int pathflow = 10000007;
            
            // Go through the path we just found. Iterate through the path.
            int v = sink;
            while(v != source)
                {
                int u = parent[v]; // The parent.
                
                // Update the pathflow to this capacity if it's smaller
                int capacity = resAdjMatrix[u][v];
                pathflow = min(pathflow, capacity);
                
                // Setup for the next edge in the path.
                v = u;
                }
            
            // 5. Update the residual capacities of the edges and reverse edges. 
            v = sink;
            while(v != source)
                {
                int u = parent[v]; // The parent.
                
                // Update the capacities.
                
                resAdjMatrix[u][v] -= pathflow;
                resAdjMatrix[v][u] += pathflow;
                
                // Setup for the next edge in the path.
                v = u;
                }
            
            // 6. Add this path's flow to our total max flow so far.
            maxflow += pathflow;
            }
        
        return maxflow;
        }
    //////////////////////////////////////////////////////////////////////////////////////////////
    
    
    //////////////////////////////////////////////////////////////////////////////////////////////    
    int main() 
        {
        cout << "Program started.\n";
        
        // Create our adjacency list.
        vector< vector<int> > adjMatrix = FormAdjMatrix();
        
        // Call FordFulkerson to get the max flow from the source to the sink.
        int source = 0;
        int sink = 6;
        
        for(int i = 0; i < 6; i++)
            {
            for(int j = 0; j < 6; j++)
                {
                int source = i;
                int sink = j;
                
                if(i == j) { continue; }
                
                cout << "The max flow from " << source << " to " << sink << " is: ";
                cout << FordFulkerson(adjMatrix, source, sink) << endl;
                }
            cout << endl;
            }
        
        
        cout << "Program ended.\n";
        
        return 0;
        }
    //////////////////////////////////////////////////////////////////////////////////////////////
    
  • 相关阅读:
    python-正则表达式
    python-定制类
    阿里云全新发布云市场能力中心,招募10个领域、500家供应商
    《DNS攻击防范科普系列3》 -如何保障 DNS 操作安全
    《DNS攻击防范科普系列2》 -DNS服务器怎么防DDoS攻击
    《DNS攻击防范科普系列1》—你的DNS服务器真的安全么?
    云栖干货回顾 |“顶级玩家”集结!分布式数据库专场精华解读
    AnalyticDB for PostgreSQL 6.0 新特性介绍
    云栖干货回顾 | 云原生数据库POLARDB专场“硬核”解析
    从零开始入门 K8s | 可观测性:你的应用健康吗?
  • 原文地址:https://www.cnblogs.com/yhm138/p/13543908.html
Copyright © 2011-2022 走看看