Cod sursa(job #1856233)

Utilizator RazvanR104Razvan-Andrei Ciocoiu RazvanR104 Data 24 ianuarie 2017 17:51:32
Problema Traseu Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.68 kb
#include <bits/stdc++.h>

using namespace std;

const int NMAX = 100, inf = 0x3f3f3f3f;

int N, M;
vector<int> G[NMAX], C[NMAX];
int in[NMAX], out[NMAX];
int dist[NMAX], rdist[NMAX];

struct flowEdge {
	int x, y, f, cap, cost;
	flowEdge *rev;
	flowEdge(int x, int y, int f, int cap, int cost, flowEdge *rev):
		x(x), y(y), f(f), cap(cap), cost(cost), rev(rev) {
	}
};
vector<flowEdge *> flowNetwork[NMAX];

void addEdge(int x, int y, int cap, int cost) {
	flowEdge *dir = new flowEdge(x, y, 0, cap, cost, 0);
	flowEdge *rev = new flowEdge(y, x, 0, 0, -cost, 0);
	dir->rev = rev;
	rev->rev = dir;
	flowNetwork[x].push_back(dir);
	flowNetwork[y].push_back(rev);
}

void graphDijkstra(int S, int *dist) {
	memset(dist, inf, (N + 1) * sizeof(int));
	priority_queue<pair<int, int>> Q;
	dist[S] = 0;
	Q.push({-dist[S], S});
	while (!Q.empty()) {
		auto now = Q.top();
		Q.pop();
		if (now.first != -dist[now.second])
			continue;
		for (int i = 0; i < int(G[now.second].size()); ++i) {
			if (dist[G[now.second][i]] > dist[now.second] + C[now.second][i]) {
				dist[G[now.second][i]] = dist[now.second] + C[now.second][i];
				Q.push({-dist[G[now.second][i]], G[now.second][i]});
			}
		}
	}
}

bool inQueue[NMAX];
void flowBellmanFord(int S, int *dist) {
	memset(dist, inf, (N + 3) * sizeof(int));
	queue<int> Q;
	Q.push(S);
	dist[S] = 0;
	inQueue[S] = 1;
	while (!Q.empty()) {
		int now = Q.front();
		Q.pop();
		inQueue[now] = 0;
		for (const auto &it: flowNetwork[now]) {
			if (it->f >= it->cap)
				continue;
			if (dist[it->y] > dist[now] + it->cost) {
				dist[it->y] = dist[now] + it->cost;
				if (!inQueue[it->y]) {
					Q.push(it->y);
					inQueue[it->y] = 1;
				}
			}
		}
	}
}

int temp[NMAX];
flowEdge *from[NMAX];
bool flowDijkstra(int S, int T, int *rdist) {
	memset(dist, inf, (N + 3) * sizeof(int));
	memset(temp, inf, (N + 3) * sizeof(int));
	priority_queue<pair<int, int>> Q;
	dist[S] = temp[S] = 0;
	Q.push({-dist[S], S});
	while (!Q.empty()) {
		auto now = Q.top();
		Q.pop();
		if (now.first != -dist[now.second])
			continue;
		for (const auto &it: flowNetwork[now.second]) {
			if (it->f >= it->cap)
				continue;
			if (dist[it->y] > dist[it->x] + rdist[it->x] - rdist[it->y] + it->cost) {
				dist[it->y] = dist[it->x] + rdist[it->x] - rdist[it->y] + it->cost;
				temp[it->y] = temp[it->x] + it->cost;
				from[it->y] = it;
				Q.push({-dist[it->y], it->y});
			}
		}
	}
	memcpy(rdist, temp, (N + 3) * sizeof(int));
	return rdist[T] != inf;
}

int maxFlowMinCost(int S, int T) {
	int flowCost = 0;
	flowBellmanFord(S, rdist);
	while (flowDijkstra(S, T, rdist)) {
		int augument = inf;
		flowEdge *curr = from[T];
		while (curr) {
			augument = min(augument, curr->cap - curr->f);
			curr = from[curr->x];
		}
		curr = from[T];
		while (curr) {
			curr->f += augument;
			curr->rev->f -= augument;
			curr = from[curr->x];
		}
		flowCost += augument * rdist[T];
	}
	return flowCost;
}

int main() {
	assert(freopen("traseu.in", "r", stdin));
	assert(freopen("traseu.out", "w", stdout));

	int i, j;
	int x, y, z;
	int answer = 0;

	cin >> N >> M;
	for (i = 0; i < M; ++i) {
		cin >> x >> y >> z;
		G[x].push_back(y);
		C[x].push_back(z);
		answer += z;
		++out[x];
		++in[y];
	}

	int S = N + 1, T = N + 2;
	for (i = 1; i <= N; ++i) {
		if (in[i] == out[i])
			continue;
		if (in[i] > out[i])
			addEdge(S, i, in[i] - out[i], 0);
		else
			addEdge(i, T, out[i] - in[i], 0);
		graphDijkstra(i, dist);
		for (j = 1; j <= N; ++j) {
			if (i == j || in[j] == out[j])
				continue;
			addEdge(i, j, inf, dist[j]);
		}
	}

	answer += maxFlowMinCost(S, T);
	cout << answer << '\n';

	return 0;
}