Cod sursa(job #2493690)

Utilizator davidegoldDavide Gold davidegold Data 16 noiembrie 2019 18:37:54
Problema Flux maxim Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.61 kb
#include <iostream>
#include <vector>

using namespace std;

/*  Problem statement: You are given a network in which edges are
 * associated capacities. You are to compute the maximum flow through the network
 * such that the following conditions are satisfied:
 *
 * 1. 0 <= flow(edge) <= capacity(edge)
 * 2. flow_in(node) = flow_out(node)
 *
 * Residual capacity: a mapping r : E -> R+, r(e) = c(e) - f(e)
 *
 * Theorem
 * ========
 * A flow network N with a flow f is a maximum flow iff there is no
 * augmenting path in the network.
 *
 * Augmenting path
 * ===============
 * Path in the network from the source to the sink
 * such that the residual capacity of every contaed edge is nonzero.
 *
 * Ford-Fulkerson description
 * ==========================
 *
 * Pseudo-code1
 * ============
 * initialize flow to zero
 * path = AugmentingPath(G, s, t)
 * while (there is an augmenting path)
 *   augment flow along path
 *   update residual capacities
 *   path = AugmentingPath(G, s, t)
 *
 *
 *Pseudo-code2
 *============
 * for each edge in the graph
 *   initialize flow to zero
 *
 * while (there is a path p from s to t in the resigual graph)
 *   augmenting_flow = min(residual_capacity((u,v)) for each edge (u,v) in the path)
 *   flow += augmenting_flow
 *   // update the residual graph
 *   for each edge (u,v) in p:
 *     if (u,v) is a forward edge:
 *       flow(u,v) += augmenting_flow;
 *     if (u,v) is backward edge:
 *       flow(u,v) -= augmenting_flow;
 * return flow
 *
 */

const int NMAX = 1e3;

struct Graph{
    int num_vertices;
    typedef long long flow_type;

    struct Edge{
        int dst;
        flow_type capacity, flow;
        size_t rev;
    };

    vector<vector<Edge>> e;

    Graph(int n) : num_vertices(n), e(n) {}

    void add_edge(int src, int dst, int capacity){
        e[src].push_back({dst, capacity, 0, e[dst].size()});
        e[dst].push_back({src, 0, 0, e[src].size()});
    }

    flow_type max_flow(int source, int sink){

        bitset<NMAX+1> vis;

        function <flow_type(int, flow_type)> aug_path = [&](int node, flow_type path_flow) {
            // check termination case when the current node is sink
            if(node == sink)
                return path_flow;

            vis.set(node);

            for(auto &edge : e[node]) {
                int son = edge.dst;
                // positive residual capacity -> can augment
                if (!vis.test(son) && edge.capacity > edge.flow) {
                    flow_type res_capacity = edge.capacity - edge.flow;
                    flow_type f = aug_path(son, min(path_flow, res_capacity));
                    // update the info for residual graph
                    if (f > 0) {
                        edge.flow += f;
                        e[edge.dst][edge.rev].flow -= f;
                        return f;
                    }
                }
            }
            return flow_type(0);
        };


        // initialize flow on each edge as zero in the beginning
        for (int i = 0; i < num_vertices; ++i)
            for (auto &edge : e[i])
                edge.flow = 0;

        flow_type flow = 0;

        while(true) {
            vis.reset(); // reset the visited nodes for the dfs
            flow_type aug_flow = aug_path(source, sink);
            if (aug_flow == 0) // test for termination case
                break;
            flow += aug_flow;

        }

        return flow;

    }

};

int main() {
    int n, m;
    cin >> n >> m;
    Graph g(n);
    for (int i = 0; i < m; ++i) {
        int x, y, c;
        cin >> x >> y >> c;
        x--, y--;
        g.add_edge(x, y, c);
    }
    cout << g.max_flow(0, n-1);
    return 0;
}