Cod sursa(job #2239658)

Utilizator freak93Adrian Budau freak93 Data 11 septembrie 2018 16:37:32
Problema Flux maxim Scor 20
Compilator cpp Status done
Runda Arhiva educationala Marime 3.95 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <queue>
#include <tuple>

using namespace std;

class Graph {
  public:
    Graph(int size):
        m_capacity(size, vector<int>(size, 0)),
        m_permitted(size, vector<int>(size, 0)),
        m_edges(size),
        m_size(size) {}

    void add_edge(int from, int to, int capacity) {
        m_capacity[from][to] += capacity;
        m_edges[from].push_back(to);
        m_edges[to].push_back(from);
    }

    int max_flow(int source, int destination) {
        int answer = 0;
        while (true) {
            auto edges = get_level_graph_edges(source, destination);

            if (edges.empty())
                return answer;

            int flow;
            do {
                flow = tidal_phase(edges, source, destination);
                answer += flow;
            } while (flow > 0);
        }
    }

  private:
    vector< pair<int, int> > get_level_graph_edges(int source, int destination) {
        // Find accessible nodes from destination, not really needed but speeds up a bit
        queue<int> Q;
        Q.push(destination);
        vector<int> level(m_size, -2);
        level[destination] = 0;
        while (!Q.empty()) {
            int x = Q.front();
            Q.pop();

            if (x == source)
                break;

            for (auto &y : m_edges[x])
                if (m_capacity[y][x] > 0 && level[y] == -2) {
                    level[y] = level[x] + 1;
                    Q.push(y);
                }
        }

        // level graph edges
        vector< pair<int, int> > edges;
        if (level[source] == -2)
            return edges;

        while (!Q.empty())
            Q.pop();
        Q.push(source);
        vector<bool> used(m_size, false);

        while (!Q.empty()) {
            int x = Q.front();
            Q.pop();

            for (auto &y : m_edges[x])
                if (m_capacity[x][y] > 0 && level[y] == level[x] - 1) {
                    edges.emplace_back(x, y);
                    if (used[y] == false) {
                        used[y] = true;
                        Q.push(y);
                    }
                }
        }
        return edges;
    }

    int tidal_phase(vector< pair<int, int> > &edges, int source, int destination) {
        vector<int> high(m_size, 0);
        high[source] = numeric_limits<int>::max();

        for (auto &edge: edges) {
            int from, to; tie(from, to) = edge;
            m_permitted[from][to] = min(high[from], m_capacity[from][to]);
            high[to] += m_permitted[from][to];
        }

        if (high[destination] == 0)
            return 0;

        vector<int> low(m_size, 0);
        low[destination] = high[destination];

        for (auto it = edges.rbegin(); it != edges.rend(); ++it) {
            int from, to; tie(from, to) = *it;
            int limit = min(high[from] - low[from], low[to]);
            m_permitted[from][to] = min(m_permitted[from][to], limit);
            low[from] += m_permitted[from][to];
            low[to] -= m_permitted[from][to];
        }

        fill(high.begin(), high.end(), 0);
        high[source] = low[source];

        for (auto &edge : edges) {
            int from, to; tie(from, to) = edge;
            m_permitted[from][to] = min(m_permitted[from][to], high[from]);
            high[from] -= m_permitted[from][to];
            high[to] += m_permitted[from][to];
            m_capacity[from][to] -= m_permitted[from][to];
            m_capacity[to][from] += m_permitted[from][to];
        }
        return high[destination];
    }

    vector< vector<int> > m_capacity, m_permitted;
    vector< vector<int> > m_edges;
    int m_size;
};

int main() {
    ifstream cin("maxflow.in");
    ofstream cout("maxflow.out");

    int N, M; cin >> N >> M;

    Graph G(N);
    for (int i = 0; i < M; ++i) {
        int x, y, capacity; cin >> x >> y >> capacity;
        G.add_edge(x - 1, y - 1, capacity);
    }

    cout << G.max_flow(0, N - 1) << "\n";
}