Cod sursa(job #1602907)

Utilizator TeodorCotetCotet Teodor TeodorCotet Data 16 februarie 2016 23:42:19
Problema Flux maxim de cost minim Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 4.57 kb
#include <fstream>
#include <iostream>
#include <vector>
#include <queue>
#include <bitset>
#include <cstring>
#include <cstdio>

using namespace std;

#define pair pair<int,int>

const int NMAX = 350;
const int MMAX = 12500;
const int INF = (1<<30);

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() {

	scanf("%d%d%d%d", &n, &m, &source, &dest);

	for(int i = 1; i <= m; ++i) {
		int x; int y; 

		scanf("%d%d", &x, &y);
		scanf("%d%d", &cap[x][y], &cost[x][y]);

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

		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];
			/*Drumurile minime se schimba de la un dijkstra la altul, de aceea trebuie schimbata si 
			distantele cu care se calculeaza.  */
		
		}
	}

	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.
	Distanta de la un nodul de start la un nod x este practic z1 + z2 + ... +zn - oldD[x] cu noile costuri
	unde z1, z2, sunt arcele drumurilor. Trebuie demonstrat ca daca z1 + z2 + ... + zn = min 
	atunci z1 + z2 + ... + zn - oldD[x]= min. Evident adevarat oldD[x] este o constanta
	*/

	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] 
		Va fi luat in considerare si trebuie sa fie si el pozitiv!!
	*/


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

		memcpy(oldD, realD, sizeof(oldD));
		/* Drumurile minime se schimba de la un dijkstra la altul, de aceea trebuie schimbata si 
			distantele cu care se calculeaza.
			Evident se schimba pentru ca desi costurile pe muchii raman la fel, se mai taie unele muchii.  */

		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() {

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

	/*Practic se cauta taietura minima 
	 the max-flow min-cut theorem states that in a flow network, the maximum amount of flow
	 passing from the source to the sink is equal to the minimum capacity that,
	 when removed in a specific way from the network, causes the situation that
	 no flow can pass from the source to the sink.
	 */

	 // Se taie muchii (si se adauga altele, inversele) pana cand nu mai poti accesa dest din sursa
	 // Complexitate: Dijkstra  O(MlogN) => O(N * M^ 2 * logN), adica trebuie sa repet de N*M
	 //idee de demonstratie a de ce trebuie sa repet de atatea ori: dupa M repetari drumul scade cu un nod.

	solve(source, dest, g);

	printf("%d", minCost);

	return 0;
}