Cod sursa(job #3155781)

Utilizator cezar_titianuTitianu Cezar cezar_titianu Data 9 octombrie 2023 17:56:22
Problema Flux maxim de cost minim Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.3 kb
#define DEBUG

#include <fstream>
#include <vector>
#include <queue>
#include <cstring>
#include <cmath>

namespace std {
	ifstream cin("fmcm.in");
	ofstream cout("fmcm.out");
};

class flux {
private:
	struct edge {
		int pos;
		int cost;
		int flux;
		int retid;
	};
	struct node {
		int dist = 0x7fffffff;
		std::vector <edge> edges;
	};
	std::vector <node> graph;
	int source, destination;

	struct path {
		int pos;
		int parid;
		int cost;

		bool operator<(const path &rhs) const {
			return cost > rhs.cost; // smallest first
		}
	};

	void calcDist() {
		std::vector <bool> in_queue(graph.size());
		std::queue <int> next;
		int now;
		next.push(source);
		in_queue[source] = true;
		graph[source].dist = 0;
		while (!next.empty()) {
			now = next.front();
			next.pop();
			in_queue[source] = false;
			for (edge chd : graph[now].edges) {
				if (graph[now].dist + chd.cost < graph[chd.pos].dist) {
					graph[chd.pos].dist = graph[now].dist + chd.cost;
					if (!in_queue[source]) {
						next.push(chd.pos);
					}
				}
			}
		}
	}

	std::vector <int> prev;
	bool findPath() {
		std::vector <bool> viz(graph.size());
		std::priority_queue <path> next;
		path now;
		next.push({source, -1, 0});
		bool found_end = false;
		while (!next.empty()) {
			now = next.top();
			next.pop();
			if (viz[now.pos]) {
				continue;
			}
			viz[now.pos] = true;
			if (now.pos == destination) {
				found_end = true;
			}
			prev[now.pos] = now.parid;
			int new_cost;
			for (edge chd : graph[now.pos].edges) {
				new_cost = now.cost + chd.cost + graph[now.pos].dist - graph[chd.pos].dist;
				if (chd.flux) {
					next.push({chd.pos, chd.retid, new_cost});
				}
			}
		}
		return found_end;
	}
	int doPath() {
		int nod, edgeid;
		int cost = 0;
		int min_flux = 0x7fffffff;

		nod = destination;
		while (nod != source) {
#ifdef DEBUG
			std::cout << nod << ' ';
#endif
			edgeid = graph[nod].edges[prev[nod]].retid;
			nod = graph[nod].edges[prev[nod]].pos;
			min_flux = std::min(min_flux, graph[nod].edges[edgeid].flux);
		}
#ifdef DEBUG
		std::cout << source << '\n';
		std::cout << cost << ' ' << min_flux << '\n';
#endif

		while (nod != source) {
			graph[nod].edges[prev[nod]].flux += min_flux;
			cost -= graph[nod].edges[prev[nod]].cost * min_flux;
			edgeid = graph[nod].edges[prev[nod]].retid;
			nod = graph[nod].edges[prev[nod]].pos;
			graph[nod].edges[edgeid].flux -= min_flux;
		}
		return cost;
	}

public:
	flux(int size, int set_source, int set_destination) {
		source = set_source;
		destination = set_destination;
		graph.resize(size);
		prev.resize(size, 0);
	}
 
	void makeEdge(int par, int chd, int cost, int flux) {
		graph[par].edges.push_back({chd, cost, flux, (int)graph[chd].edges.size()});
		graph[chd].edges.push_back({par, -cost, 0, (int)graph[par].edges.size() - 1});
	}

	int doFlux() {
		calcDist();
		int ans = 0;
		while (findPath()) {
			ans += doPath();
			memset(&prev[0], 0x00, prev.size() * sizeof(int));
		}
		return ans;
	}
};

int main() {
	int n, m, s, d;
	std::cin >> n >> m >> s >> d;
	flux sol(n, --s, --d);
	int nod, chd, flx, cost;
	for (int i = 0; i < m; i++) {
		std::cin >> nod >> chd >> flx >> cost;
		sol.makeEdge(--nod, --chd, cost, flx);
	}
	std::cout << sol.doFlux();
}