Cod sursa(job #2049314)

Utilizator retrogradLucian Bicsi retrograd Data 27 octombrie 2017 00:51:33
Problema Flux maxim de cost minim Scor 70
Compilator cpp Status done
Runda Arhiva educationala Marime 2.96 kb
/**
 * Author: Stanford
 * Date: Unknown
 * Source: Stanford Notebook
 * Description: Min-cost max-flow. cap[i][j] != cap[j][i] is allowed; double edges are not.
 *  If costs can be negative, call setpi before maxflow, but note that negative cost cycles are not allowed (that's NP-hard).
 *  To obtain the actual flow, look at positive values only.
 * Status: Tested on kattis mincostmaxflow
 * Time: Approximately O(E^2)
 */
#include <bits/stdc++.h>

using namespace std;

using T = int;
const T kInf = numeric_limits<T>::max() / 4;

struct MFMC {
	int n;
    vector<vector<T>> C, F, K;
    vector<vector<int>> G;
    
    vector<T> dist, pi;
    vector<int> par;

	MFMC(int n) :
		n(n), C(n, vector<T>(n, 0)), F(C), K(C),
		G(n), dist(n), pi(n), par(n) {}

	void AddEdge(int from, int to, T cap, T cost) {
		C[from][to] = cap;
		K[from][to] = cost;
        K[to][from] = -cost;
		G[from].push_back(to);
		G[to].push_back(from);
	}

	bool dijkstra(int s, int t) {
		fill(dist.begin(), dist.end(), kInf);
        fill(par.begin(), par.end(), -1);
        priority_queue<pair<T, int>> q;

		dist[s] = 0; q.emplace(0, s);
        while (!q.empty()) {
            int node; T d; 
            tie(d, node) = q.top(); q.pop();
            if (dist[node] != -d) continue;
            for (auto vec : G[node]) {
                T now = dist[node] + pi[node] - pi[vec] + K[node][vec];
                if (F[node][vec] < C[node][vec] && now < dist[vec]) {
                    dist[vec] = now;
                    par[vec] = node;
                    q.emplace(-dist[vec], vec);
                }
            }
            
        } 
        for (int i = 0; i < n; ++i)
            pi[i] = min(pi[i] + dist[i], kInf);
        return par[t] != -1;
	}

	pair<T, T> Compute(int s, int t) {
		T flow = 0, cost = 0;
		while (dijkstra(s, t)) {
			T now = kInf;
            for (int node = t; node != s; node = par[node])
                now = min(now, C[par[node]][node] - F[par[node]][node]);
            for (int node = t; node != s; node = par[node]) {
                F[par[node]][node] += now;
                F[node][par[node]] -= now;
                cost += now * K[par[node]][node];
            }
            flow += now;
		}
		return {flow, cost};
	}

	// If some costs can be negative, call this before maxflow:
	void SetPi(int s) { // (otherwise, leave this out)
        fill(pi.begin(), pi.end(), kInf); pi[s] = 0;
		int it = n, ch = 1; T v;
		while (ch-- && it--)
			for (int i = 0; i < n; ++i) if (pi[i] != kInf)
				for (auto vec : G[i]) if (C[i][vec])
					if ((v = pi[i] + K[i][vec]) < pi[vec])
						pi[vec] = v, ch = 1;
		assert(it >= 0); // negative cost cycle
	}
};

int main() {
    ifstream cin("fmcm.in");
    ofstream cout("fmcm.out");
    int n, m, s, d; cin >> n >> m >> s >> d;
    MFMC flow(n);
    while (m--) {
        int a, b, c, k; cin >> a >> b >> c >> k;
        flow.AddEdge(a - 1, b - 1, c, k);
    }
    flow.SetPi(s - 1);
    auto p = flow.Compute(s - 1, d - 1);
    cout << p.second << endl;
    return 0;
}