Cod sursa(job #1601727)

Utilizator TeodorCotetCotet Teodor TeodorCotet Data 16 februarie 2016 10:48:06
Problema Flux maxim de cost minim Scor 70
Compilator cpp Status done
Runda Arhiva educationala Marime 3.26 kb
#include <fstream>
#include <iostream>
#include <vector>
#include <queue>
#include <bitset>
#include <cstring>

using namespace std;

ifstream fin("fmcm.in");
ofstream fout("fmcm.out");

#define pair pair<int,int>

const int NMAX = 350;
const int MMAX = 12500;
const int INF = 0x7fffffff;

int n; int m; int source; int dest;

int cap[NMAX + 1][NMAX + 1];
int flow[NMAX + 1][NMAX + 1];
int cost[NMAX + 1][NMAX + 1];
/* res graph = cost - flow */

vector< vector<int> > g(NMAX + 1, vector<int>(0));

int before[NMAX + 1]; 

int oldD[NMAX + 1]; int realD[NMAX + 1];

priority_queue< pair , vector< pair > , greater< pair > > pq;

int minCost;
void read() {

	fin >> n >> m >> source >> dest;

	for(int i = 1; i <= m; ++i) {
		int x; int y; int capacity; int c;
		fin >> x >> y >> capacity >> c;

		cap[x][y] = capacity;
		cost[x][y] = c;
		cost[y][x] = -c;

		g[x].push_back(y);
		g[y].push_back(x);
	}
}

void bellmanFord(int sursa, int dest, vector< vector<int> >& g) {

	queue<int> q;
	bitset<NMAX + 1> inQueue;

	for(int i = 1; i <= n; ++i)
		oldD[i] = INF;

	q.push(sursa);
	inQueue[sursa] = true;
	oldD[sursa] = 0;

	while(q.empty() == false) {

		int node = q.front();
		q.pop();

		inQueue[node] = false;

		for(int x : g[node]) 
			if(cap[node][x] && oldD[node] + cost[node][x] < oldD[x]) {

				oldD[x] = oldD[node] + cost[node][x];

				if(inQueue[x] == false) {
					q.push(x);
					inQueue[x] = true;
				}
			}
	}
}

bool dijkstra(int start, int dest, vector< vector<int> >& g) {

	vector<int> dist(NMAX + 1, INF);
	/* We use this to calculate the real distance realD. We don t need this calculations. */

	pq.push({0, start});
	dist[start] = realD[start] = 0;
	before[start] = start;

	while(pq.empty() == false) {

		int node = pq.top().second;
		int dst = pq.top().first;
		
		pq.pop();

		if(dst < dist[node]) continue;

		for(int x : g[node]) { 

			int maxFlow = cap[node][x] - flow[node][x];

			if(maxFlow <= 0) continue;

			int d = dist[node] + cost[node][x] + oldD[node] - oldD[x];

			if(d >= dist[x]) continue;

			dist[x] = d;
			pq.push({dist[x], x});
			before[x] = node;
			realD[x] = realD[node] + cost[node][x];
		
		}
	}

	return (dist[dest] != INF);
}

void solve(int start, int dest, vector< vector<int> >& g) {

	/* Precalculez distantele cu BellmanFord apoi asociez muchiei x->y costul 
	cost[x][y] + oldD[x] - oldD[y] > 0. Drumurile minime nu se modifica. Se demonstreaza prin RA.
	*/

	bellmanFord(start, dest, g);

	/* Desi nu a fost luat in considerare si costul invers in bellmanforst, din ecuatii da si el pozitiv
		cost[j][i] = -cost[i][j] + oldD[j] - oldD[i], oldD[j] > oldD[i] + cost[i][j] */


	while(dijkstra(start, dest, g)) {

		memcpy(oldD, realD, sizeof(oldD));

		int x = dest; int maxFlow = INF;

		while(before[x] != x) {
			maxFlow = min(maxFlow, cap[before[x]][x] - flow[before[x]][x]);
			x = before[x];
		}

		x = dest;

		minCost += maxFlow * realD[dest];

		while(before[x] != x) {

			flow[before[x]][x] += maxFlow;
			flow[x][before[x]] -= maxFlow;
			x = before[x];
		}
	}
	
}

int main() {

	ios_base::sync_with_stdio(false);
	
	read();

	solve(source, dest, g);

	fout << minCost << '\n'; 

	return 0;
}