Cod sursa(job #2753488)

Utilizator preda.andreiPreda Andrei preda.andrei Data 23 mai 2021 00:41:41
Problema Flux maxim de cost minim Scor 70
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.69 kb
#include <cstring>
#include <fstream>
#include <queue>
#include <vector>

using namespace std;

constexpr auto kMaxNodes = 351;

struct Graph {
    vector<vector<int>> edges;
    vector<vector<int>> ordered;
    int cap[kMaxNodes][kMaxNodes];
    int cost[kMaxNodes][kMaxNodes];
    vector<int> dist;

    Graph(int nodes)
        : edges(nodes),
          ordered(nodes),
          dist(nodes, 1 << 30) {}

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

    int OgCost(int x, int y) const {
        return cost[x][y] - (dist[x] - dist[y]);
    }
};

template <typename T>
using MinHeap = priority_queue<T, vector<T>, greater<T>>;

void MakeCostsPositive(Graph& graph, int source, int sink) {
    graph.dist[source] = 0;

    queue<int> q;
    q.push(source);

    vector<bool> in_q(graph.Size(), false);
    in_q[source] = true;

    while (!q.empty()) {
        auto node = q.front();
        q.pop();
        in_q[node] = false;

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

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

bool FindPath(Graph& graph, int source, int sink, vector<int>& pred) {
    pred.assign(graph.Size(), -1);

    int cost[kMaxNodes];
    memset(cost, 0x3f, sizeof(cost));
    cost[source] = 0;

    MinHeap<pair<int, int>> q;
    q.push({cost[source], source});

    while (!q.empty()) {
        auto node = q.top().second;
        auto q_cost = q.top().first;
        q.pop();

        if (q_cost > cost[node]) {
            continue;
        }

        for (const auto& next : graph.edges[node]) {
            if (graph.cap[node][next] <= 0) {
                continue;
            }

            if (cost[node] + graph.cost[node][next] < cost[next]) {
                cost[next] = cost[node] + graph.cost[node][next];
                pred[next] = node;
                q.push({cost[next], next});
            }
        }
    }
    return pred[sink] >= 0;
}

int FlowCost(Graph& graph, int sink, const vector<int>& pred) {
    auto a = pred[sink];
    auto b = sink;
    auto cost = 0;
    auto flow = graph.cap[a][b];

    while (a >= 0) {
        flow = min(flow, graph.cap[a][b]);
        cost += graph.OgCost(a, b);
        b = a;
        a = pred[a];
    }

    a = pred[sink];
    b = sink;
    while (a >= 0) {
        graph.cap[a][b] -= flow;
        graph.cap[b][a] += flow;
        b = a;
        a = pred[a];
    }

    return flow * cost;
}

int MinCostMaxFlow(Graph& graph, int source, int sink) {
    MakeCostsPositive(graph, source, sink);

    int min_cost = 0;
    vector<int> pred;
    while (FindPath(graph, source, sink, pred)) {
        min_cost += FlowCost(graph, sink, pred);
    }

    return min_cost;
}

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

    int nodes, edges, source, sink;
    fin >> nodes >> edges >> source >> sink;

    Graph graph(nodes);
    for (int i = 0; i < edges; i += 1) {
        int a, b, cap, cost;
        fin >> a >> b >> cap >> cost;

        graph.edges[a - 1].push_back(b - 1);
        graph.edges[b - 1].push_back(a - 1);
        graph.ordered[a - 1].push_back(b - 1);
        graph.cap[a - 1][b - 1] = cap;
        graph.cost[a - 1][b - 1] = cost;
        graph.cost[b - 1][a - 1] = -cost;
    }

    auto cost = MinCostMaxFlow(graph, source - 1, sink - 1);
    fout << cost << "\n";

    return 0;
}