Cod sursa(job #1976646)

Utilizator crushackPopescu Silviu crushack Data 3 mai 2017 22:11:47
Problema Flux maxim de cost minim Scor 50
Compilator cpp Status done
Runda Arhiva educationala Marime 3.57 kb
#include <bits/stdc++.h>

using namespace std;

template <class T, T INF=0x3f3f3f3f>
class MaxFlowMinimalCost {
	typedef vector<vector<int>> Graph;
	typedef unordered_map<size_t, unordered_map<size_t, T>> SparseMatrix;

	T flow_val_;
	T cost_val_;

	Graph graph_;
	SparseMatrix capacity_;
	SparseMatrix flow_;
	SparseMatrix cost_;

	vector<T> read_dist;

public:

	MaxFlowMinimalCost(size_t n) {
		graph_.resize(n + 1);
	}

	virtual void add_edge(size_t x, size_t y, T capacity, T cost) {
		graph_[x].push_back(y);
		graph_[y].push_back(x);

		capacity_[x][y] += capacity;
		capacity_[y][x] += 0;

		cost_[x][y] = cost;
		cost_[y][x] = -cost;
	}

	SparseMatrix get_flow() {
		return flow_;
	}

	vector<T> bellmanFord(int start) {
		queue<size_t> q;

		vector<size_t> parent(graph_.size(), 0);
		vector<T> dist(graph_.size(), INF);

		vector<bool> in_queue(graph_.size(), false);

		q.push(start);
		in_queue[start] = true;
		dist[start] = 0;

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

			for (size_t neigh : graph_[node]) {
				if (flow_[node][neigh] < capacity_[node][neigh] && dist[node] + cost_[node][neigh] < dist[neigh]) {
					dist[neigh] = dist[node] + cost_[node][neigh];
					parent[neigh] = node;

					if (!in_queue[neigh]) {
						in_queue[neigh] = true;
						q.push(neigh);
					}
				}
			}

			in_queue[node] = false;
		}

		return dist;
	}

	vector<size_t> dijkstra(int start, vector<T>& bellman_cost) {
		vector<T> dist(graph_.size(), INF);
		vector<size_t> parent(graph_.size(), 0);
		priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;

		read_dist.resize(graph_.size());

		dist[start] = 0;
		read_dist[start] = 0;

		q.push({dist[start], start});

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

			q.pop();

			if (dist[node] != cost) {
				continue;
			}

			for (size_t neigh : graph_[node]) {
				if (flow_[node][neigh] < capacity_[node][neigh]) {
					int new_dist = dist[node] + cost_[node][neigh] + bellman_cost[node] - bellman_cost[neigh];

					if (new_dist < dist[neigh]) {
						dist[neigh] = new_dist;
						read_dist[neigh] = read_dist[node] + cost_[node][neigh];
						parent[neigh] = node;

						q.push({dist[neigh], neigh});
					}
				}
			}
		}

		bellman_cost = read_dist;

		return parent;
	}


	pair<T, T> do_flow(size_t start, size_t finish) {
		T flow = 0;
		T cost = 0;

		auto bellman_cost = bellmanFord(start);

		while (true) {
			auto parent = dijkstra(start, bellman_cost);

			if (parent[finish] == 0) {
				break;
			}

			T fmin = INF;

			for (size_t node = finish; node != start; node = parent[node]) {
				fmin = min(fmin, capacity_[parent[node]][node] - flow_[parent[node]][node]);
			}

			if (fmin == 0) {
				continue;
			}

			for (size_t node = finish; node != start; node = parent[node]) {
				flow_[parent[node]][node] += fmin;
				flow_[node][parent[node]] -= fmin;
			}

			flow += fmin;
			cost += read_dist[finish] * fmin;
		}

		flow_val_ = flow;	
		cost_val_ = cost;

		return {flow, cost};
	}
};

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

	int n, m, start, finish;

	cin >> n >> m >> start >> finish;

	MaxFlowMinimalCost<int> flow(n);

	for (int i = 0; i < m; ++ i) {
		int x, y, cap, cost;

		cin >> x >> y >> cap >> cost;
		flow.add_edge(x, y, cap, cost);
	}

	auto res = flow.do_flow(start, finish);

	// cerr << res.first << endl;
	cout << res.second << endl;

	return 0;
}