Cod sursa(job #831278)

Utilizator alex_unixPetenchea Alexandru alex_unix Data 8 decembrie 2012 13:28:12
Problema Flux maxim de cost minim Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 4.56 kb

#include <cstdio>
#include <vector>

const int MAX_SIZE(351);
const int MAX_VALUE(1 << 30);
const int MAX_CAPACITY(10000);

int n, m, source, sink, min_cost;
long long maxflow;

int cost [MAX_SIZE] [MAX_SIZE];
int capacity [MAX_SIZE] [MAX_SIZE];
int min_path [MAX_SIZE];
int heap [MAX_SIZE], heap_size;
int heap_position [MAX_SIZE];
int queue [MAX_SIZE * MAX_SIZE];
bool in_queue [MAX_SIZE];
int pred [MAX_SIZE];

std::vector<int> graph [MAX_SIZE];

inline void read (void)
{
	std::freopen("fmcm.in","r",stdin);
	std::scanf("%d %d %d %d",&n,&m,&source,&sink);
	int x, y, c, z;
	for (int counter(0) ; counter < m ; ++counter)
	{
		std::scanf("%d %d %d %d",&x,&y,&c,&z);
		graph[x].push_back(y);
		graph[y].push_back(x);
		capacity[x][y] = c;
		cost[x][y] = z;
		cost[y][x] = -z;
	}
	std::fclose(stdin);
}

inline void print (void)
{
	std::freopen("fmcm.out","w",stdout);
	std::printf("%lld\n",maxflow);
	std::fclose(stdout);
}

inline void BellmanFord (void)
{
	int index, size;
	for (index = 1 ; index <= n ; ++index)
		min_path[index] = MAX_VALUE;
	min_path[source] = 0;
	*queue = source;
	in_queue[source] = true;
	int *pop(queue), *push(queue + 1), vertex, neighbor;
	while (pop < push)
	{
		vertex = *pop;
		++pop;
		for (index = 0, size = graph[vertex].size() ; index < size ; ++index)
			if (capacity[vertex][graph[vertex][index]] && min_path[vertex] + cost[vertex][graph[vertex][index]] < min_path[graph[vertex][index]])
			{
				neighbor = graph[vertex][index];
				min_path[neighbor] = min_path[vertex] + cost[vertex][neighbor];
				if (!in_queue[neighbor])
				{
					*push = neighbor;
					++push;
					in_queue[neighbor] = true;
				}
			}
		in_queue[vertex] = false;
	}
	min_cost = min_path[sink];
}

inline void initialize (void)
{
	int index, vertex, size;
	for (index = 1 ; index <= n ; ++index)
		if (min_path[index] != MAX_VALUE)
			for (vertex = 0, size = graph[index].size() ; vertex < size ; ++vertex)
				if (min_path[graph[index][vertex]] != MAX_VALUE)
					cost[index][graph[index][vertex]] += min_path[index] - min_path[graph[index][vertex]];
	for (index = 1 ; index <= n ; ++index)
	{
		min_path[index] = MAX_VALUE;
		heap[index - 1] = index;
		heap_position[index] = index - 1;
	}
	min_path[source] = 0;
	if (source > 1)
	{
		*heap = source;
		heap_position[source] = 0;
		heap[source - 1] = 1;
		heap_position[1] = source - 1;
	}
	heap_size = n;
}

inline void swap (int &a, int &b)
{
	int temp(a);
	a = b;
	b = temp;
}

inline void up (int index)
{
	if (index)
	{
		int father((index - 1) >> 1), vertex(heap[index]);
		while (true)
		{
			if (min_path[vertex] < min_path[heap[father]])
			{
				heap[index] = heap[father];
				swap(heap_position[heap[father]],heap_position[vertex]);
			}
			else
				break;
			index = father;
			if (father)
			{
				--father;
				father >>= 1;
			}
			else
				break;
		}
		heap[index] = vertex;
	}
}

inline void down (int index)
{
	int left((index << 1) + 1), right(left + 1), smallest;
	while (true)
	{
		if (left < heap_size && min_path[heap[left]] < min_path[heap[index]])
			smallest = left;
		else
			smallest = index;
		if (right < heap_size && min_path[heap[right]] < min_path[heap[smallest]])
			smallest = right;
		if (smallest == index)
			break;
		swap(heap_position[heap[smallest]],heap_position[heap[index]]);
		swap(heap[index],heap[smallest]);
		index = smallest;
		left = (index << 1) + 1;
		right = left + 1;
	}
}

inline void pop (void)
{
	--heap_size;
	*heap = heap[heap_size];
	down(0);
}

inline void Dijkstra (void)
{
	initialize();
	int vertex, neighbor;
	int index, size;
	while (heap_size)
	{
		vertex = *heap;
		pop();
		for (index = 0, size = graph[vertex].size() ; index < size ; ++index)
			if (capacity[vertex][graph[vertex][index]] && min_path[vertex] + cost[vertex][graph[vertex][index]] < min_path[graph[vertex][index]])
			{
				neighbor = graph[vertex][index];
				min_path[neighbor] = min_path[vertex] + cost[vertex][neighbor];
				pred[neighbor] = vertex;
				up(heap_position[neighbor]);
			}
	}
}

inline void FordFulkerson (void)
{
	int vertex, path_capacity;
	while (true)
	{
		Dijkstra();
		if (min_path[sink] == MAX_VALUE)
			break;
		min_cost += min_path[sink];
		path_capacity = MAX_CAPACITY;
		for (vertex = sink ; vertex != source ; vertex = pred[vertex])
			if (capacity[pred[vertex]][vertex] < path_capacity)
				path_capacity = capacity[pred[vertex]][vertex];
		for (vertex = sink ; vertex != source ; vertex = pred[vertex])
		{
			capacity[pred[vertex]][vertex] -= path_capacity;
			capacity[vertex][pred[vertex]] += path_capacity;
		}
		maxflow += min_cost * path_capacity;
	}
}

int main (void)
{
	read();
	BellmanFord();
	FordFulkerson();
	print();
}