Cod sursa(job #2473635)

Utilizator preda.andreiPreda Andrei preda.andrei Data 13 octombrie 2019 22:35:58
Problema Flux maxim de cost minim Scor 50
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.87 kb
#include <fstream>
#include <queue>
#include <vector>

using namespace std;

struct Graph
{
    vector<vector<int>> capacity;
    vector<vector<int>> costs;
    vector<vector<int>> original_costs;
    vector<vector<bool>> is_normal;

    Graph(int nodes)
        : capacity(nodes, vector<int>(nodes, 0)),
          costs(nodes, vector<int>(nodes, 0)),
          original_costs(nodes, vector<int>(nodes, 0)),
          is_normal(nodes, vector<bool>(nodes, false)) {}

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

    void AddEdge(int a, int b, int cap, int cost)
    {
        capacity[a][b] = cap;
        costs[a][b] = cost;
        costs[b][a] = -cost;
        original_costs[a][b] = costs[a][b];
        original_costs[b][a] = costs[b][a];
        is_normal[a][b] = true;
    }
};

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

vector<int> BellmanFord(const Graph &g, int start)
{
    vector<int> total(g.Size(), (1 << 30));
    total[start] = 0;

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

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

        for (int next = 0; next < g.Size(); next += 1) {
            if (g.costs[node][next] == 0 || !g.is_normal[node][next]) {
                continue;
            }
            if (total[node] + g.costs[node][next] < total[next]) {
                total[next] = total[node] + g.costs[node][next];
                q.push(next);
            }
        }
    }
    return total;
}

void MakeCostsPositive(Graph &g, int source)
{
    auto total = BellmanFord(g, source);
    for (int i = 0; i < g.Size(); i += 1) {
        for (int j = 0; j < g.Size(); j += 1) {
            if (g.is_normal[i][j] || g.is_normal[j][i]) {
                g.costs[i][j] += total[i] - total[j];
            }
        }
    }
}

bool FindPaths(const Graph &g, int source, int dest, vector<int> &pred)
{
    pred.assign(g.Size(), -1);

    vector<int> costs(g.Size(), (1 << 30));
    costs[source] = 0;

    MinHeap<pair<int, int>> q;
    q.push({0, source});

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

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

        for (int next = 0; next < g.Size(); next += 1) {
            if (g.capacity[node][next] <= 0) {
                continue;
            }
            if (cost + g.costs[node][next] < costs[next]) {
                costs[next] = cost + g.costs[node][next];
                pred[next] = node;
                q.push({costs[next], next});
            }
        }
    }
    return pred[dest] != -1;
}

int MinCapacity(const Graph &g, int dest, const vector<int> &pred)
{
    int node = pred[dest];
    int cap = g.capacity[node][dest];

    while (node >= 0) {
        cap = min(cap, g.capacity[node][dest]);
        dest = node;
        node = pred[node];
    }
    return cap;
}

int FlowCost(Graph &g, int dest, const vector<int> &pred)
{
    int cap = MinCapacity(g, dest, pred);
    int node = pred[dest];
    int cost = 0;

    while (node >= 0) {
        cost += cap * g.original_costs[node][dest];
        g.capacity[node][dest] -= cap;
        g.capacity[dest][node] += cap;

        dest = node;
        node = pred[node];
    }
    return cost;
}

int MinCostFlow(Graph &g, int source, int dest)
{
    int cost = 0;
    vector<int> pred;

    MakeCostsPositive(g, source);
    while (FindPaths(g, source, dest, pred)) {
        cost += FlowCost(g, dest, pred);
    }
    return cost;
}

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

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

    Graph graph(nodes);
    for (int 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 cost = MinCostFlow(graph, source - 1, dest - 1);
    fout << cost << "\n";

    return 0;
}