Pagini recente » Cod sursa (job #632283) | Cod sursa (job #745573) | Cod sursa (job #3170670) | Cod sursa (job #2556121) | Cod sursa (job #2900918)
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
struct MCMF {
struct Edge {
int to, flow, cap, cost;
};
vector<Edge> edges;
vector<vector<int>> adj;
int source, sink;
const int INF = 2e9 + 7;
vector<int> realdist, fakedist, dist;
vector<int> prev, viz;
MCMF(int _n) {
source = _n + 3; sink = _n + 4;
adj.resize(_n + 7);
realdist.resize(_n + 7);
fakedist.resize(_n + 7);
dist.resize(_n + 7);
prev.resize(_n + 7);
viz.resize(_n + 7);
}
void add_edge(int from, int to, int cap, int cost) {
edges.push_back({to, 0, cap, cost}); adj[from].push_back(edges.size() - 1);
edges.push_back({from, 0, 0, -cost}); adj[to].push_back(edges.size() - 1);
}
void make_source(int node) { add_edge(source, node, INF, 0); }
void make_sink(int node) { add_edge(node, sink, INF, 0); }
void bellman() {
for(auto &e : dist) e = INF;
vector<bool> inq(sink + 3);
queue<int> q; q.push(source);
dist[source] = 0;
while(!q.empty()) {
auto node = q.front(); q.pop();
inq[node] = false;
for(auto eid : adj[node]) {
auto edge = edges[eid];
if(edge.cap > edge.flow && dist[edge.to] > dist[node] + edge.cost) {
dist[edge.to] = dist[node] + edge.cost;
if(inq[edge.to] == false) {
q.push(edge.to); inq[edge.to] = true;
}
}
}
}
}
bool dijkstra() {
priority_queue<pair<int, int>> pq;
for(auto &e : prev) e = -1;
for(auto &e : viz) e = false;
for(int i = 0; i < dist.size(); ++i) realdist[i] = dist[i];
for(auto &e : fakedist) e = INF;
dist[source] = fakedist[source] = 0;
pq.push({ -0, source });
while(!pq.empty()) {
int node = pq.top().second; pq.pop();
if(viz[node] == false) {
viz[node] = true;
for(auto eid : adj[node]) {
auto edge = edges[eid];
if(edge.cap > edge.flow && (prev[edge.to] == -1 || fakedist[node] + realdist[node] + edge.cost - realdist[edge.to] < fakedist[edge.to])) {
prev[edge.to] = eid ^ 1;
fakedist[edge.to] = fakedist[node] + realdist[node] + edge.cost - realdist[edge.to];
dist[edge.to] = dist[node] + edge.cost;
pq.push({ -fakedist[edge.to], edge.to });
}
}
}
}
return fakedist[sink] != INF;
}
pair<int64_t, int64_t> get_flow_cost() {
int64_t flow = 0, cost = 0;
bellman();
while(dijkstra()) {
int64_t cnt_flow = INF, cnt_cost = 0;
for(int node = sink; node != source; node = edges[prev[node]].to) {
auto edge = edges[prev[node] ^ 1];
cnt_cost += edge.cost;
cnt_flow = min(cnt_flow, (int64_t)edge.cap - edge.flow);
}
for(int node = sink; node != source; node = edges[prev[node]].to) {
auto eid = prev[node] ^ 1;
edges[eid].flow += cnt_flow;
edges[eid ^ 1].flow -= cnt_flow;
}
flow += cnt_flow;
cost += cnt_flow * cnt_cost;
}
return {flow, cost};
}
};
#ifndef LOCAL
ifstream in("fmcm.in");
ofstream out("fmcm.out");
#define cin in
#define cout out
#endif // LOCAL
int main() {
int n, m, s, d;
cin >> n >> m >> s >> d;
MCMF sol(n + 3);
sol.make_source(s);
sol.make_sink(d);
for(int i = 0; i < m; i++) {
int u, v, cap, cost; cin >> u >> v >> cap >> cost;
sol.add_edge(u, v, cap, cost);
}
auto ans = sol.get_flow_cost();
cerr << ans.first << " ";
cout << ans.second << endl;
return 0;
}