Cod sursa(job #1219748)

Utilizator abel1090Abel Putovits abel1090 Data 14 august 2014 23:03:46
Problema Flux maxim de cost minim Scor 70
Compilator cpp Status done
Runda Arhiva educationala Marime 3.96 kb
///FMCM
#include <iostream>
#include <fstream>
#include <vector>
#include <list>
#include <queue>
#include <limits>

using namespace std;

const short INF = numeric_limits<short>::max();

struct Edge {
	short to, cost;

	Edge(short to, short cost) {
		this -> to = to;
		this -> cost = cost;
	}
};

class CompEdges {
public:
	bool operator () (Edge& a, Edge& b) { return a.cost > b.cost; }
};

vector<short> getSignedDistances(vector<list<Edge> >& adjList,
		vector<vector<unsigned> >& capacities, short source) {
	vector<short> distances(adjList.size(), INF);
	vector<bool> inQueue(adjList.size(), false);
	queue<short> q;

	q.push(source);
	distances[source] = 0;

	short current;
	list<Edge>::iterator it;
	while(!q.empty()) {
		current = q.front();
		q.pop();
		inQueue[current] = false;

		for(it = adjList[current].begin(); it != adjList[current].end(); it++)
			if(capacities[current][it -> to] > 0 &&
					distances[current] + it -> cost < distances[it -> to]) {
				distances[it -> to] = distances[current] + it -> cost;

				if(!inQueue[it -> to]) {
					q.push(it -> to);
					inQueue[it -> to] = true;
				}
			}
	}

	return distances;
}

unsigned getCurrentFlow(vector<vector<unsigned> >& capacities,
		vector<short>& previous, short sink) {
	unsigned currentFlow = numeric_limits<unsigned>::max();

	short prev;
	while(previous[sink] > -1) {
		prev = previous[sink];
		currentFlow = min(currentFlow, capacities[prev][sink]);
		sink = prev;
	}

	return currentFlow;
}

void updateNetwork(vector<vector<unsigned> >& capacities,
		vector<short>& previous, short sink, unsigned flow) {
	short prev;
	while(previous[sink] > -1) {
		prev = previous[sink];
		capacities[prev][sink] -= flow;
		capacities[sink][prev] += flow;
		sink = prev;
	}
}

int getMinimalCost(vector<list<Edge> >& adjList,
		vector<vector<unsigned> >& capacities,
		vector<short>& signedDist, short source, short sink) {
	int minimalCost = 0;
	unsigned currentFlow;
	bool isAugmentedPath = true;

	while(isAugmentedPath) {
		isAugmentedPath = false;

		vector<unsigned> modDist(adjList.size(), INF);
		vector<int> distances(adjList.size(), INF);
		vector<short> previous(adjList.size(), -1);
		priority_queue<Edge, vector<Edge>, CompEdges> heap;

		modDist[source] = 0;
		distances[source] = 0;
		heap.push(Edge(source, modDist[source]));

		short current;
		int currCost;
		unsigned modCost;
		list<Edge>::iterator it;
		while(!heap.empty()) {
			current = heap.top().to;
			currCost = heap.top().cost;
			heap.pop();

			if(currCost != modDist[current])
				continue;

			if(current == sink) {
				isAugmentedPath = true;
				break;
			}

			for(it = adjList[current].begin(); it != adjList[current].end(); it++)
				if(capacities[current][it -> to] > 0) {
					modCost = it -> cost + signedDist[current] - signedDist[it -> to];
					if(modCost + modDist[current] < modDist[it -> to]) {
						modDist[it -> to] = modCost + modDist[current];
						distances[it -> to] = distances[current] + it -> cost;
						heap.push(Edge(it -> to, modDist[it -> to]));
						previous[it -> to] = current;
					}
				}
		}

		if(isAugmentedPath) {
			currentFlow = getCurrentFlow(capacities, previous, sink);
			updateNetwork(capacities, previous, sink, currentFlow);

			minimalCost += distances[sink] * currentFlow;
		}
	}


	return minimalCost;
}

int main() {
	ifstream inStr("fmcm.in");
	ofstream outStr("fmcm.out");

	short numNodes, numEdges, source, sink;
	inStr >> numNodes >> numEdges >> source >> sink;
	--source; --sink;

	vector<list<Edge> > adjList(numNodes);
	vector<vector<unsigned> > capacities(numNodes, vector<unsigned>(numNodes, 0));
	vector<short> distances(numNodes);

	short from, to, cost;
	unsigned cap;
	for(short i=0; i < numEdges; i++) {
		inStr >> from >> to >> cap >> cost;
		adjList[--from].push_back(Edge(--to, cost));
		adjList[to].push_back(Edge(from, -cost));
		capacities[from][to] = cap;
	}

	distances = getSignedDistances(adjList, capacities, source);
	outStr << getMinimalCost(adjList, capacities, distances, source, sink) << '\n';

	return 0;
}