Cod sursa(job #1251228)

Utilizator gabrieligabrieli gabrieli Data 29 octombrie 2014 08:15:24
Problema Flux maxim de cost minim Scor 10
Compilator cpp Status done
Runda Arhiva educationala Marime 6.5 kb
#include <iostream>
#include <algorithm>
#include <fstream>
#include <functional>
#include <iterator>
#include <limits>
#include <queue>
#include <utility>
#include <vector>
using namespace std;

struct Reweighting {
    const vector<vector<int>>& initialCost;
    const vector<int>& h;
    
    Reweighting(const vector<vector<int>>& cost,
                const vector<int>& h) : initialCost(cost), h(h) {}
    
    int operator()(const int u, const int v) const {
        return initialCost[u][v] + h[u] - h[v];
    }
};

vector<int> bellman_ford(
        const int source,
        const vector<vector<int>>& capacity,
        const vector<vector<int>>& cost,
        const vector<vector<int>>& G);

pair<vector<int>, vector<int>> dijkstra(
        const int source,
        const vector<vector<int>>& capacity,
        const vector<vector<int>>& cost,
        const Reweighting& positiveWeights,
        const vector<vector<int>>& G);

inline int findResidualCapacity(
        int start,
        const vector<int>& tree,
        const vector<vector<int>>& capacity);

inline int augmentFlow(
        int start,
        const int residualCapacity,
        const vector<int>& tree,
        const vector<vector<int>>& cost,
        vector<vector<int>>& capacity);

pair<int, int> minCostMaxFlow(
        const int source,
        const int sink,
        vector<vector<int>>& capacity,
        vector<vector<int>>& cost,
        const vector<vector<int>>& G);

int main() {
    ifstream fin("fmcm.in");
    ofstream fout("fmcm.out");
    
    int n, m, source, sink;
    fin >> n >> m >> source >> sink; source--; sink--;
    
    // residual network
    vector<vector<int>> G(n),
                        capacity(n, vector<int>(n, 0)),
                        cost(n, vector<int>(n, 0));
                        
    for (int u, v, c, z; m; --m) {
        fin >> u >> v >> c >> z; u--; v--;
        
        capacity[u][v] = c;
        cost[u][v] = z;
        cost[v][u] = -z;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    
    pair<int, int> result = minCostMaxFlow(source, sink, capacity, cost, G);
    
    fout << result.first << endl;
    
    return 0;
}

pair<int, int> minCostMaxFlow(
        const int source,
        const int sink,
        vector<vector<int>>& capacity,
        vector<vector<int>>& cost,
        const vector<vector<int>>& G) {
    vector<int> tree;
    int minCost = 0, maxFlow = 0;
    // reweighting to obtain non-negative costs
    // the new weight function produces the same shortest paths
    vector<int> h = bellman_ford(source, capacity, cost, G);
    
    while (true) {
        // find augmenting paths
        pair<vector<int>, vector<int>> t = dijkstra(
                source, capacity, cost, Reweighting(cost, h), G);
        h.swap(t.first);
        tree.swap(t.second);
        
        // if there are no more paths which reach the sink
        if (tree[sink] == -1) break;
        
        // check all augmenting paths which end at a neighbour of the sink
        for (int u : G[sink]) if (capacity[u][sink]) {
            int residualCapacity = findResidualCapacity(u, tree, capacity);    
            if (residualCapacity == 0) continue;
            
            // augment the flow
            residualCapacity = min(residualCapacity, capacity[u][sink]);
            
            capacity[u][sink] -= residualCapacity;
            capacity[sink][u] += residualCapacity;
            minCost += augmentFlow(u, residualCapacity, tree, cost, capacity);
            minCost += cost[u][sink] * residualCapacity;
            
            maxFlow += residualCapacity;
        }
    }
    
    return make_pair(minCost, maxFlow);
}

inline int findResidualCapacity(
        int start,
        const vector<int>& tree,
        const vector<vector<int>>& capacity) {
    int residualCapacity = numeric_limits<int>::max();
    
    for (; start != tree[start] && residualCapacity; start = tree[start])
        residualCapacity = min(residualCapacity, capacity[tree[start]][start]);
    
    return residualCapacity;
}

inline int augmentFlow(
        int start,
        const int residualCapacity,
        const vector<int>& tree,
        const vector<vector<int>>& cost,
        vector<vector<int>>& capacity) {
    int residualCost = 0;
    for (; start != tree[start]; start = tree[start]) {
        capacity[tree[start]][start] -= residualCapacity;
        capacity[start][tree[start]] += residualCapacity;
        
        residualCost += cost[tree[start]][start] * residualCapacity;
    }
    return residualCost;
}

pair<vector<int>, vector<int>> dijkstra(
        const int source,
        const vector<vector<int>>& capacity,
        const vector<vector<int>>& cost,
        const Reweighting& positiveWeights,
        const vector<vector<int>>& G) {
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> Q;
    vector<int> D(G.size(), numeric_limits<int>::max()),
                realD(G.size()),
                P(G.size(), -1);
    
    D[source] = realD[source] = 0;
    P[source] = source;
    Q.push(make_pair(D[source], source));
    
    while (!Q.empty()) {
        pair<int, int> next = Q.top(); Q.pop();  
        int d = next.first, u = next.second;
        
        if (D[u] == d) for (int v : G[u])
            if (capacity[u][v] && D[v] > D[u] + positiveWeights(u, v)) {
                D[v] = D[u] + positiveWeights(u, v);
                realD[v] = realD[u] + cost[u][v];
                Q.push(make_pair(D[v], v));
                
                P[v] = u;
            }
    }
    
    return make_pair(realD, P);
}

vector<int> bellman_ford(
        const int source,
        const vector<vector<int>>& capacity,
        const vector<vector<int>>& cost,
        const vector<vector<int>>& G) {
    int iterations, n = G.size();
    bool ok;
    vector<int> D(n, numeric_limits<int>::max());
    vector<int> changed, next_changed;
    vector<bool> in_changed(n);
    
    D[source] = 0;
    changed.push_back(source);
    
    for (iterations = 0, ok = true; iterations <= n && ok; ++iterations) {
        ok = false;
        next_changed.clear();
        fill(in_changed.begin(), in_changed.end(), false);
        
        for (int u : changed) for (int v : G[u])
            if (capacity[u][v] && D[v] > D[u] + cost[u][v]) {
                ok = true;
                D[v] = D[u] + cost[u][v];
                
                if (!in_changed[v]) {
                    next_changed.push_back(v);
                    in_changed[v] = true;
                }
            }
        changed.swap(next_changed);
    }
    
    return D;
}