Pagini recente » Cod sursa (job #332558) | Cod sursa (job #945313) | Cod sursa (job #247807) | Cod sursa (job #733035) | Cod sursa (job #2753488)
#include <cstring>
#include <fstream>
#include <queue>
#include <vector>
using namespace std;
constexpr auto kMaxNodes = 351;
struct Graph {
vector<vector<int>> edges;
vector<vector<int>> ordered;
int cap[kMaxNodes][kMaxNodes];
int cost[kMaxNodes][kMaxNodes];
vector<int> dist;
Graph(int nodes)
: edges(nodes),
ordered(nodes),
dist(nodes, 1 << 30) {}
int Size() const {
return edges.size();
}
int OgCost(int x, int y) const {
return cost[x][y] - (dist[x] - dist[y]);
}
};
template <typename T>
using MinHeap = priority_queue<T, vector<T>, greater<T>>;
void MakeCostsPositive(Graph& graph, int source, int sink) {
graph.dist[source] = 0;
queue<int> q;
q.push(source);
vector<bool> in_q(graph.Size(), false);
in_q[source] = true;
while (!q.empty()) {
auto node = q.front();
q.pop();
in_q[node] = false;
for (const auto& next : graph.ordered[node]) {
if (graph.dist[node] + graph.cost[node][next] < graph.dist[next]) {
graph.dist[next] = graph.dist[node] + graph.cost[node][next];
if (!in_q[next]) {
q.push(next);
in_q[next] = true;
}
}
}
}
for (int i = 0; i < graph.Size(); i += 1) {
for (const auto& j : graph.edges[i]) {
graph.cost[i][j] += graph.dist[i] - graph.dist[j];
}
}
}
bool FindPath(Graph& graph, int source, int sink, vector<int>& pred) {
pred.assign(graph.Size(), -1);
int cost[kMaxNodes];
memset(cost, 0x3f, sizeof(cost));
cost[source] = 0;
MinHeap<pair<int, int>> q;
q.push({cost[source], source});
while (!q.empty()) {
auto node = q.top().second;
auto q_cost = q.top().first;
q.pop();
if (q_cost > cost[node]) {
continue;
}
for (const auto& next : graph.edges[node]) {
if (graph.cap[node][next] <= 0) {
continue;
}
if (cost[node] + graph.cost[node][next] < cost[next]) {
cost[next] = cost[node] + graph.cost[node][next];
pred[next] = node;
q.push({cost[next], next});
}
}
}
return pred[sink] >= 0;
}
int FlowCost(Graph& graph, int sink, const vector<int>& pred) {
auto a = pred[sink];
auto b = sink;
auto cost = 0;
auto flow = graph.cap[a][b];
while (a >= 0) {
flow = min(flow, graph.cap[a][b]);
cost += graph.OgCost(a, b);
b = a;
a = pred[a];
}
a = pred[sink];
b = sink;
while (a >= 0) {
graph.cap[a][b] -= flow;
graph.cap[b][a] += flow;
b = a;
a = pred[a];
}
return flow * cost;
}
int MinCostMaxFlow(Graph& graph, int source, int sink) {
MakeCostsPositive(graph, source, sink);
int min_cost = 0;
vector<int> pred;
while (FindPath(graph, source, sink, pred)) {
min_cost += FlowCost(graph, sink, pred);
}
return min_cost;
}
int main() {
ifstream fin("fmcm.in");
ofstream fout("fmcm.out");
int nodes, edges, source, sink;
fin >> nodes >> edges >> source >> sink;
Graph graph(nodes);
for (int i = 0; i < edges; i += 1) {
int a, b, cap, cost;
fin >> a >> b >> cap >> cost;
graph.edges[a - 1].push_back(b - 1);
graph.edges[b - 1].push_back(a - 1);
graph.ordered[a - 1].push_back(b - 1);
graph.cap[a - 1][b - 1] = cap;
graph.cost[a - 1][b - 1] = cost;
graph.cost[b - 1][a - 1] = -cost;
}
auto cost = MinCostMaxFlow(graph, source - 1, sink - 1);
fout << cost << "\n";
return 0;
}