Cod sursa(job #2907151)

Utilizator preda.andreiPreda Andrei preda.andrei Data 28 mai 2022 22:27:35
Problema Flux maxim de cost minim Scor 50
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.59 kb
#include <fstream>
#include <iostream>
#include <queue>
#include <set>
#include <vector>

using namespace std;

struct Graph {
    vector<vector<int>> edges;
    vector<vector<int>> ordered;
    vector<vector<int>> cap;
    vector<vector<int>> cost;
    vector<int> h;
    int src;
    int dst;

    Graph(int nodes, int src, int dst)
        : edges(nodes), ordered(nodes), cap(nodes, vector<int>(nodes, 0)),
          cost(nodes, vector<int>(nodes, 0)), src(src), dst(dst) {
    }

    int Size() const {
        return edges.size();
    }

    void AddEdge(int a, int b, int cap, int cost) {
        this->edges[a].push_back(b);
        this->edges[b].push_back(a);
        this->ordered[a].push_back(b);
        this->cap[a][b] = cap;
        this->cost[a][b] = cost;
        this->cost[b][a] = -cost;
    }
};

vector<int> BellmanFord(const Graph& graph) {
    vector<int> dist(graph.Size(), 1 << 30);
    dist[graph.src] = 0;

    queue<int> q;
    q.push(graph.src);

    while (!q.empty()) {
        auto node = q.front();
        q.pop();

        for (const auto& next : graph.ordered[node]) {
            auto new_dist = dist[node] + graph.cost[node][next];
            if (new_dist < dist[next]) {
                dist[next] = new_dist;
                q.push(next);
            }
        }
    }
    return dist;
}

vector<pair<int, int>> FindPath(const Graph& graph) {
    vector<int> dist(graph.Size(), 1 << 30);
    vector<int> prev(graph.Size(), -1);
    multiset<pair<int, int>> heap;

    dist[graph.src] = 0;
    heap.insert({dist[graph.src], graph.src});

    while (!heap.empty()) {
        auto kk = heap.begin()->first;
        auto node = heap.begin()->second;
        heap.erase(heap.begin());
        if (kk > dist[node]) {
            continue;
        }

        for (const auto& next : graph.edges[node]) {
            auto new_dist = dist[node] + graph.cost[node][next];
            if (new_dist < dist[next] && graph.cap[node][next] > 0) {
                dist[next] = new_dist;
                prev[next] = node;
                heap.insert({dist[next], next});
            }
        }
    }

    vector<pair<int, int>> path;
    for (auto node = graph.dst; prev[node] >= 0; node = prev[node]) {
        path.push_back({prev[node], node});
    }
    return path;
}

int Flow(Graph& graph, const vector<pair<int, int>>& path) {
    auto flow = 1 << 30;
    for (const auto& edge : path) {
        flow = min(flow, graph.cap[edge.first][edge.second]);
    }

    auto cost = 0;
    for (const auto& edge : path) {
        auto a = edge.first;
        auto b = edge.second;
        cost += flow * (graph.cost[a][b] - (graph.h[a] - graph.h[b]));
        graph.cap[a][b] -= flow;
        graph.cap[b][a] += flow;
    }
    return cost;
}

int MaxFlow(Graph& graph) {
    auto cost = 0;
    auto path = FindPath(graph);
    while (!path.empty()) {
        cost += Flow(graph, path);
        path = FindPath(graph);
    }
    return cost;
}

int Solve(Graph& graph) {
    auto h = BellmanFord(graph);
    for (auto i = 0; i < graph.Size(); i += 1) {
        for (const auto& j : graph.edges[i]) {
            graph.cost[i][j] += h[i] - h[j];
        }
    }
    graph.h = h;

    return MaxFlow(graph);
}

int main() {
    ifstream fin("fmcm.in");
    ofstream fout("fmcm.out");

    int nodes, edges;
    fin >> nodes >> edges;

    int src, dst;
    fin >> src >> dst;

    Graph graph(nodes, src - 1, dst - 1);
    for (auto i = 0; i < edges; i += 1) {
        int a, b, cap, cost;
        fin >> a >> b >> cap >> cost;
        graph.AddEdge(a - 1, b - 1, cap, cost);
    }

    auto res = Solve(graph);
    fout << res << "\n";
    return 0;
}