Cod sursa(job #2961849)

Utilizator CosminaBuruianaCosmina Buruiana CosminaBuruiana Data 7 ianuarie 2023 03:28:10
Problema Flux maxim de cost minim Scor 20
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.95 kb
#include <queue>
#include <vector>
#include <climits>
#include <fstream>

using namespace std;

ifstream fin("fmcm.in");
ofstream fout("fmcm.out");

#define N_MAX    351
#define INFINITY INT_MAX


int N, M, src, dest;
vector<int> neighbors[N_MAX];

// Min Cost for Max Flow
int min_cost, max_flux;
int parent[N_MAX], capacity[N_MAX][N_MAX], cost[N_MAX][N_MAX];

// Bellman Ford
int old_dist[N_MAX];

// Dijkstra
int dist[N_MAX], real_cost[N_MAX];


bool dijkstra() {
	auto comparator = [](int lhs, int rhs) {
		return dist[lhs] > dist[rhs];
	};
	static auto heap = priority_queue<int,
		vector<int>, decltype(comparator)>(comparator);

	for (int i = 1; i <= N; ++i) {
		dist[i] = INFINITY;
	}

	dist[src] = 0;
	real_cost[src] = 0;
    heap.push(src);

    while (!heap.empty()) {
        int node = heap.top();
        heap.pop();

		for (auto neigh : neighbors[node]) {
			// the capacity is exhausted or
			// there is no residual flow to push back
            if (capacity[node][neigh] == 0)
				continue;

			int new_dist = dist[node] + cost[node][neigh]
				+ old_dist[node] - old_dist[neigh];
            
			if (dist[neigh] > new_dist) {
                dist[neigh]      = new_dist;
                real_cost[neigh] = real_cost[node] + cost[node][neigh];
            	parent[neigh]    = node;

				heap.push(neigh);
            }
		}
    }

	return dist[dest] != INFINITY;
}

void bellmanFord() {
    bool inQueue[N_MAX];
	queue<int> queue;

	for (int i = 1; i <= N; ++i) {
		old_dist[i] = INFINITY;
		inQueue[i] = false;
	}

	queue.push(src);
	old_dist[src] = 0;
	inQueue[src] = true;
    
    while (!queue.empty()) {
        int node = queue.front();
		queue.pop();
        inQueue[node] = false;

        for (auto neigh : neighbors[node]) {
			// this is an actual edge, not a residual one
			if (capacity[node][neigh] == 0)
				continue;

			// this cost distance is not much better than the previously one
			if (old_dist[neigh] <= old_dist[node] + cost[node][neigh])
				continue;

			old_dist[neigh] = old_dist[node] + cost[node][neigh];

			// the neigh is already in queue
			if (inQueue[neigh])
				continue;

			inQueue[neigh] = true;
            queue.push(neigh);
		}
    }
}

int main() {
	int x, y, c, z, min_flux;

	fin >> N >> M >> src >> dest;

	for (int i = 0; i < M; ++i) {
		fin >> x >> y >> c >> z;

		neighbors[x].push_back(y);
		neighbors[y].push_back(x);
    
		capacity[x][y] = c;
		cost[x][y] =  z;
		cost[y][x] = -z;
    }

    bellmanFord();

    for (min_cost = 0, max_flux = 0; dijkstra();) {
		min_flux = INFINITY;

		for (int i = 1; i <= N; ++i) {
			old_dist[i] = real_cost[i];
		}

   		for (int node = dest; node != src; node = parent[node]) {
        	min_flux = min(min_flux, capacity[parent[node]][node]);
		}

		for (int node = dest; node != src; node = parent[node]) {
			capacity[parent[node]][node] -= min_flux;
			capacity[node][parent[node]] -= min_flux;
		}

		max_flux += min_flux;
		min_cost += min_flux * real_cost[dest];
	}

	fout << min_cost;

    return 0;
}