Cod sursa(job #1408132)

Utilizator AlexandruValeanuAlexandru Valeanu AlexandruValeanu Data 29 martie 2015 20:16:59
Problema Flux maxim de cost minim Scor 70
Compilator cpp Status done
Runda Arhiva educationala Marime 3.01 kb

#include <iostream>
#include <fstream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <cstring>
#include <cassert>
#include <utility>
#include <iomanip>

using namespace std;

const int MAXN = 1050;
const long long INF = (long long) 1e15;

struct edge {
	int from, to;
	int flow, cap;
	long long cost;
};

int n;
int cost[MAXN][MAXN];
vector <edge> e;
vector <int> g[MAXN];
long long phi[MAXN];
priority_queue < pair < long long, int > > q;
long long dist[MAXN];
int par[MAXN];
int edge_num;
int N, M, S, T;

void fordBellman() {
	for (int i = 1; i <= N; i++)
		dist[i] = INF;
	dist[S] = 0;
	while (true) {
		bool change = false;
		for (int i = 0; i < edge_num; i++) {
			int from = e[i].from, to = e[i].to;
			if (e[i].flow == e[i].cap)
				continue;
			if (dist[from] == INF)
				continue;
			if (dist[to] > dist[from] + e[i].cost) {
				dist[to] = dist[from] + e[i].cost;
				change = true;
			}
		}
		if (!change)
			break;
	}
}

void dijkstra() {
	while (!q.empty())
		q.pop();
	for (int i = 1; i <= N; i++) {
		dist[i] = INF;
		q.push(make_pair(-dist[i], i));
	}
	dist[S] = 0;
	q.push(make_pair(0, S));
	while (!q.empty()) {
		int cur = q.top().second;
		long long cur_dist = -q.top().first;
		q.pop();
		if (cur_dist > dist[cur])
			continue;
		if (dist[cur] == INF)
			break;
		for (int i = 0; i < (int) g[cur].size(); i++) {
			int ind = g[cur][i];
			if (e[ind].flow == e[ind].cap)
				continue;
			int to = e[ind].to;
			long long w = e[ind].cost + phi[cur] - phi[to];
			if (cur_dist + w < dist[to]) {
				dist[to] = cur_dist + w;
				par[to] = ind;
				q.push(make_pair(-dist[to], to));
			}
		}
	}
}

long long minCost(int flow) {
	long long result = 0;

	fordBellman();
	for (int i = 1; i <= N; i++)
		phi[i] = dist[i];

	while (true) {

		dijkstra();

		if (dist[T] == INF)
			return result;

		for (int i = 1; i <= N; i++)
			phi[i] = min(phi[i] + dist[i], INF);

		int push = flow;
		int cur = T;
		while (cur != S) {
			edge tmp = e[par[cur]];
			int from = tmp.from, can_push = tmp.cap - tmp.flow;
			push = min(push, can_push);
			cur = from;
		}

		flow -= push;
		cur = T;
		while (cur != S) {
			edge tmp = e[par[cur]];
			int from = tmp.from;
			e[par[cur]].flow += push;
			e[par[cur] ^ 1].flow -= push;
			result += 1ll * push * tmp.cost;
			cur = from;
		}

		if (flow == 0)
			break;
	}
	return result;
}

void addEdge(int from, int to, int cap, long long cost) {
	edge tmp;
	tmp.from = from; tmp.to = to; tmp.flow = 0; tmp.cap = cap; tmp.cost = cost;
	e.push_back(tmp);
	g[from].push_back(edge_num);

	tmp.from = to; tmp.to = from; tmp.flow = cap; tmp.cap = cap; tmp.cost = -cost;
	e.push_back(tmp);
	g[to].push_back(edge_num + 1);

	edge_num += 2;
}

int main()
{
    ifstream f("fmcm.in");
    ofstream g("fmcm.out");

    f >> N >> M >> S >> T;

    for ( int i = 1, a, b, c, d; i <= M; ++i )
    {
        f >> a >> b >> c >> d;

        addEdge(a, b, c, d);
    }

    g << minCost(1000000000);

    return 0;
}