Cod sursa(job #425753)

Utilizator laserbeamBalan Catalin laserbeam Data 26 martie 2010 07:36:18
Problema Flux maxim de cost minim Scor 20
Compilator cpp Status done
Runda Arhiva educationala Marime 4.84 kb
// Catalin Balan
// Thu Mar 25 17:29:08 EET 2010
// Flux Maxim de Cost Minim

#include <cstdio>
#include <cstdlib>
#include <vector>
#include <queue>

using namespace std;

#define NMAX 355
#define CHUNK 8192
#define INF 0x3f3f3f3f

#define FIN "fmcm.in"
#define FOUT "fmcm.out"

typedef long long i64;

char g_buf[CHUNK];
int g_p=CHUNK-1;

int Cap[NMAX][NMAX]; // Cap[i][j] = Capacitatea arcului i -> j
int Flux[NMAX][NMAX]; // Fluxul curent pe arcul i -> j
int Cost[NMAX][NMAX]; // Costul pe arcul i -> j
vector<int> G[NMAX]; // graful...
int Heap[NMAX], Poz[NMAX], L; // heapul si pozitiile in care se afla elementele in heap
int source, sink, n, m, amGasitDrum;
int Parent[NMAX]; // vector de parinti
int sum; // cand schimb costurile z cu z + dist[x] - dist[y]... un drum de la sursa la destinatie o sa difere printr-o constanta
		 // care initial e distanta de la sursa la destinatie
int Dist[NMAX]; // distanta de la sursa la i
bool inQ[NMAX]; // verifica daca un nod e in coada de la bellman ford

// parsare
inline int get()
{

	int x = 0;
	int alpha = 1;
	while ((g_buf[g_p] < '0' || g_buf[g_p] > '9') && g_buf[g_p] != '-')
		if (++g_p == CHUNK) fread(g_buf,1,CHUNK,stdin), g_p=0;

	if (g_buf[g_p] == '-')
	{
		alpha = -1;
		if (++g_p == CHUNK) fread(g_buf,1,CHUNK,stdin), g_p=0;
	}

	while (g_buf[g_p] >= '0' && g_buf[g_p] <= '9')
	{
		x = x*10 + g_buf[g_p]-'0';
		if (++g_p == CHUNK) fread(g_buf,1,CHUNK,stdin), g_p=0;
	}
	return x * alpha;
}

// schimba 2 elemente din heap
void swapH( int a, int b )
{
	int aux = Heap[a];
	Heap[a] = Heap[b];
	Heap[b] = aux;

	Poz[Heap[a]] = a;
	Poz[Heap[b]] = b;
}

// urca in heap
void upheap( int p )
{
	while (p>>1 && Dist[Heap[p>>1]] > Dist[Heap[p]])
	{
		swapH(p, p>>1);
		p >>= 1;
	}
}

// coboara in heap
void downheap( int p)
{
	int q = 0, w;
	while (p != q)
	{
		q = p;
		w =  p<<1;	 	if ( w <= L && Dist[Heap[w]] < Dist[Heap[p]]) p = w;
		w = (p<<1)+1; 	if ( w <= L && Dist[Heap[w]] < Dist[Heap[p]]) p = w;
		swapH(q, p);
	}
}

// parcurgere initiala - cand am arce negative
void belmanFord()
{
	int now;
	queue<int> Q;
	vector<int>::iterator it;
	
	Q.push(source);
	inQ[source] = true;
	
	for (int i = 1; i <= n; ++i) Dist[i] = INF;
	Dist[source] = 0;

	while (!Q.empty())
	{
		now = Q.front(); 
		Q.pop();
		inQ[now] = false;

		for (it = G[now].begin(); it != G[now].end(); ++it)
		{
			if ( Cap[now][*it] == 0 ||  Dist[*it] <= Dist[now] + Cost[now][*it] ) continue;
			Dist[*it] = Dist[now] + Cost[now][*it];
			
			if ( inQ[*it] ) continue;
			Q.push(*it);
			inQ[*it] = true;
		}
	}
	sum = Dist[sink];
}

int Dijkstra()
{
	vector<int>::iterator it;
	
	// modifica costurile
	for (int i = 1; i <= n; ++i)
		for (it = G[i].begin(); it != G[i].end(); ++it)
			if (Dist[i] != INF && Dist[*it] != INF) Cost[i][*it] += Dist[i] - Dist[*it];


	// initialize
	for (int i = 1; i <= n; ++i)
	{
		Dist[i] = INF;
		Heap[i] = Poz[i] = i;
		Parent[i] = 0;
	}

	Dist[source] = 0;
	swapH(1, source);
	L = n;

	/*
	for (int i = 1; i <= n; ++i)
	{
		for (int j = 1; j <= n; ++j)
			fprintf(stderr, "%d ", Cap[i][j]);
		fprintf(stderr, "\n");
	}
	fprintf(stderr, "\n");
	for (int i = 1; i <= n; ++i)
	{
		for (int j = 1; j <= n; ++j)
			fprintf(stderr, "%d ", Flux[i][j]);
		fprintf(stderr, "\n");
	}
	fprintf(stderr, "\n");
	for (int i = 1; i <= n; ++i)
	{
		for (int j = 1; j <= n; ++j)
			fprintf(stderr, "%d ", Cost[i][j]);
		fprintf(stderr, "\n");
	}
	*/

	// fa daickstra : )
	while ( L > 1 && Dist[Heap[1]] != INF)
	{
		int nod = Heap[1];
		swapH(1, L);
		downheap(1);
		--L;
		for (it = G[nod].begin(); it != G[nod].end(); ++it)
		{
			if (Cap[nod][*it] > Flux[nod][*it] && (Dist[nod] + Cost[nod][*it]) < Dist[*it])
			{
				Dist[*it] = Dist[nod] + Cost[nod][*it];
				Parent[*it] = nod;
				upheap(Poz[*it]);
			}
		}
	}

	/*
	for (int i = 1; i <= n; ++i)
		fprintf(stderr, "%d ", Dist[i]);
	fprintf(stderr, "\n");

	for (int i = 1; i <= n; ++i)
		fprintf(stderr, "%d ", Parent[i]);
	fprintf(stderr, "\n---------------\n");
	*/

	// gasit-am drum?
	if (Dist[sink] != INF)
	{
		amGasitDrum = 1;
		int fmin = INF;
		for (int i = sink; i != source; i = Parent[i])
			fmin = min( fmin, Cap[Parent[i]][i] - Flux[Parent[i]][i] );

		for (int i = sink; i != source; i = Parent[i])
		{
			Flux[Parent[i]][i] += fmin;
			Flux[i][Parent[i]] -= fmin;
		}

		sum += Dist[sink];
		return fmin * sum;

	}

	return 0;

}

// cauta drumuri cat timp mai sunt si actualizeaza costul
i64 solve()
{
	i64 rez = 0;
	amGasitDrum = 1;
	while (amGasitDrum)
	{
		amGasitDrum = 0;
		rez += Dijkstra();
	}
	
	return rez;
}

int main(int argv, char ** argc)
{
	freopen(FIN, "r", stdin);
	freopen(FOUT, "w", stdout);

	n = get();
	m = get();
	source = get();
	sink = get();
	for (;m;--m)
	{
		int x = get();
		int y = get();
		Cap[x][y] = get();
		Cap[y][x] = 0;
		Cost[x][y] = get();
		Cost[y][x] = -Cost[x][y];
		G[x].push_back(y);
		G[y].push_back(x);
	}
	
	belmanFord();
	
	printf("%lld\n", solve());

	
	return EXIT_SUCCESS;
}