Cod sursa(job #2689406)

Utilizator Constantin.Dragancea Constantin Constantin. Data 20 decembrie 2020 17:15:12
Problema Flux maxim de cost minim Scor 70
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.96 kb
#include <bits/stdc++.h>
using namespace std;

class InParser{
private:
	FILE *fin;
	char *buff;
	int sp;
	
	char read_ch(){
		if (++sp == 4096)
			sp = 0, fread(buff, 1, 4096, fin);
		return buff[sp];
	}
public:
	InParser (const char* nume){
		fin = fopen(nume, "r");
		buff = new char[4096];
		sp = 4095;
	}
	
	InParser& operator>> (int &n){
		char c;
		while (!isdigit(c = read_ch()) && c != '-');
		int sgn = 1;
		if (c == '-')
			n = 0, sgn = -1;
		else
			n = c - '0';
		while (isdigit(c = read_ch()))
			n = 10 * n + c - '0';
		
		n *= sgn;
		return *this;
	}
};

struct Graph{
	int n, s, d;
	vector < vector <int> > graph;
	vector < vector <int> > cap, cost;
	vector <int> dist, dist2, pr;
	queue < pair <int, int> > Q;
	priority_queue < pair <int, int> > S;
	
	Graph(int _n, int _s, int _d): n(_n), s(_s), d(_d), graph(n), 
		cap(n, vector <int>(n)), cost(n, vector <int>(n)), 
		dist(n), dist2(n), pr(n) { }
	
	void AddEdge(int a, int b, int cp, int cst){
		graph[a].push_back(b);
		graph[b].push_back(a);
		cap[a][b] += cp;
		cost[a][b] = cst;
		cost[b][a] = -cst;
	}
	
	void Bellman(){
		fill(dist.begin(), dist.end(), 1e9);
		vector <bool> vis(n);
		Q.push({0, s});
		dist[s] = 0;
		vis[s] = 1;
		
		while (!Q.empty()){
			int curr_cost = Q.front().first;
			int node = Q.front().second;
			Q.pop();
			
			if (curr_cost != dist[node])
				continue;
			
			for (auto nei: graph[node]){
				if (!cap[node][nei])
					continue;
				int new_cost = curr_cost + cost[node][nei];
				if (new_cost < dist[nei]){
					dist[nei] = curr_cost;
					if (!vis[nei]){
						Q.push({dist[nei], nei});
						vis[nei] = 1;
					}
				}
			}
			vis[node] = 0;
		}
	}
	
	int Dijkstra(){
		fill(dist2.begin(), dist2.end(), 1e9);
		
		S.push({0, s});
		dist2[s] = 0;
		pr[s] = -1;
		
		while (!S.empty()){
			int curr_cost = -S.top().first;
			int node = S.top().second;
			S.pop();
			
			if (curr_cost != dist2[node])
				continue;
				
			for (auto nei: graph[node]){
				if (!cap[node][nei])
					continue;
				int new_cost = curr_cost + cost[node][nei] + dist[node] - dist[nei];
				if (new_cost < dist2[nei]){
					dist2[nei] = new_cost;
					pr[nei] = node;
					S.push({-dist2[nei], nei});
				}
			}
		}
		
		if (dist2[d] == 1e9)
			return 0;
		
		int flow = 1e9;
		int path_cost = 0;
		
		for (int node = d; node != s; node = pr[node])
			flow = min(flow, cap[pr[node]][node]);
		
		for (int node = d; node != s; node = pr[node]){
			cap[pr[node]][node] -= flow;
			cap[node][pr[node]] += flow;
			path_cost += cost[pr[node]][node];
		}
		
		dist = dist2;
		
		return flow * path_cost;
	}
	
	int MinCostMaxFlow(){
		Bellman();
		int ans = 0;
		
		while (auto iterate = Dijkstra()){
			ans += iterate;
		}
		
		return ans;
	}
	
};

int main(){
	InParser cin("fmcm.in");
	ofstream cout("fmcm.out");
	
	int n, m, s, d;
	cin >> n >> m >> s >> d;
	s--; d--;
	Graph G(n, s, d);
	
	while(m--){
		int a, b, c, z;
		cin >> a >> b >> c >> z;
		a--; b--;
		G.AddEdge(a, b, c, z);
	}
	
	cout << G.MinCostMaxFlow() << '\n';
	
	return 0;
}