Cod sursa(job #3040771)

Utilizator FunnyStockyMihnea Andreescu FunnyStocky Data 30 martie 2023 13:52:45
Problema Flux maxim de cost minim Scor 90
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.98 kb
#include <cmath>
#include <functional>
#include <fstream>
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <set>
#include <map>
#include <list>
#include <time.h>
#include <math.h>
#include <random>
#include <deque>
#include <cassert>
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <stack>
#include <chrono>
#include <cstring>
#include <numeric>


using namespace std;

struct MCMF {
	struct Edge {
		int to, cap, cost;
	};
	int n;
	int s;
	int d;
	vector<Edge> edges;
	vector<vector<int>> g;
	long long flow = 0;
	long long cost = 0;
	const long long INFLL = (long long)1e18 + 7;
	vector<long long> dist;
	vector<long long> odist;
	vector<int> parid;

	void init(int _n, int _s, int _d) {
		n = _n;
		s = _s;
		d = _d;
		assert(0 <= s && s < n);
		assert(0 <= d && d < n);
		assert(s != d);
		dist.clear();
		odist.clear();
		edges.clear();
		g.clear();
		g.resize(n);
		dist.resize(n);
		odist.resize(n);
		parid.resize(n);
		flow = 0;
		cost = 0;
	}

	void addedge(int from, int to, int cap, int cost) {
		assert(0 <= from && from < n);
		assert(0 <= to && to < n);
		edges.push_back({ to, cap, cost });
		edges.push_back({ from, 0, -cost });

		g[from].push_back((int)edges.size() - 2);
		g[to].push_back((int)edges.size() - 1);
	}

	void belf() {
		for (int i = 0; i < n; i++) {
			dist[i] = INFLL;
			parid[i] = -1;
		}
		vector<bool> inq(n, false);
		queue<int> q;
		auto relax = [&](int v, long long d, int i) {

			if (d < dist[v]) {
				dist[v] = d;
				if (!inq[v]) q.push(v);
				parid[v] = i;
			}
		};

		relax(s, 0, -1);
		while (!q.empty()) {
			int a = q.front();
			q.pop();
			inq[a] = false;
			for (auto& i : g[a]) {
				assert(0 <= i && i < (int)edges.size());
				if (edges[i].cap > 0) {
					relax(edges[i].to, dist[a] + edges[i].cost, i);
				}
			}
		}
	}

	void dijk() {
		for (int i = 0; i < n; i++) {
			odist[i] = dist[i];
			dist[i] = INFLL;
			parid[i] = -1;
		}
		priority_queue<pair<long long, int>> pq;
		auto relax = [&](int v, long long d, int i) {

			if (d < dist[v]) {
				dist[v] = d;
				pq.push({ -dist[v], v });
				parid[v] = i;
			}
		};

		relax(s, 0, -1);
		while (!pq.empty()) {
			pair<long long, int> it = pq.top();
			pq.pop();
			if (-it.first != dist[it.second]) {
				continue;
			}
			int a = it.second;
			for (auto& i : g[a]) {
				assert(0 <= i && i < (int)edges.size());
				if (edges[i].cap > 0) {
					int b = edges[i].to;
					//assert(odist[a] - odist[b] + edges[i].cost >= 0);
					relax(edges[i].to, dist[a] + odist[a] - odist[b] + edges[i].cost, i);
				}
			}
		}
		for (int i = 0; i < n; i++) {
			dist[i] += odist[i];
		}
	}

	bool push() {
		dijk();
		if (dist[d] >= INFLL) {
			return false;
		}
		int cur = d;
		int mn = (int)1e9;
		while (cur != s) {
			int i = parid[cur];
			assert(edges[i].to == cur);
			assert(edges[i ^ 1].to != cur);
			assert(edges[i].cap > 0);
			mn = min(mn, edges[i].cap);
			cur = edges[i ^ 1].to;
		}
		assert(mn >= 1);
		flow += mn;
		cost += mn * (long long)dist[d];
		cur = d;
		while (cur != s) {
			int i = parid[cur];
			assert(edges[i].to == cur);
			assert(edges[i ^ 1].to != cur);
			edges[i].cap -= mn;
			edges[i ^ 1].cap += mn;
			cur = edges[i ^ 1].to;
		}
		return true;
	}
	void solve() {
		belf();
		while (push()) {

		}
	}
};
signed main() {
#ifdef ONPC	
	FILE* stream;
	freopen_s(&stream, "input.txt", "r", stdin);
#else
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);

	freopen("fmcm.in", "r", stdin);
	freopen("fmcm.out", "w", stdout);

#endif

	int n, m, s, d;
	cin >> n >> m >> s >> d;
	MCMF f;
	f.init(n, s - 1, d - 1);
	for (int i = 0; i < m; i++) {
		int a, b, c, d;
		cin >> a >> b >> c >> d;
		a--;
		b--;
		f.addedge(a, b, c, d);
	}
	f.solve();
	//cout << f.flow << "\n";
	cout << f.cost << "\n";

	return 0;
}