Cod sursa(job #2776194)

Utilizator retrogradLucian Bicsi retrograd Data 18 septembrie 2021 20:00:32
Problema Flux maxim de cost minim Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.72 kb
#include <bits/stdc++.h>
 
using namespace std;
const int INF = 1e9; // greater than sum(e.k), INF * sum(sup) should fit
using ll = int;

struct NetworkSimplex {
  struct Edge { int a, b, c, k, f = 0; };
 
  int n;
  vector<int> pei, nxt;
  vector<ll> dual;
  vector<Edge> E;
  vector<set<int>> tree;
  vector<int> stk;
  
  NetworkSimplex(int n) : 
    n(n), pei(n + 1, -1), nxt(n + 1, -1),
    dual(n + 1, 0), tree(n + 1) {}
  
  int AddEdge(int a, int b, int c, int k) {
    E.push_back({a, b, c, k});
    E.push_back({b, a, 0, -k});
    return E.size() - 2;
  }
  void build(int ei = -1) {
    stk.push_back(ei);
    while (stk.size()) {
      int ei = stk.back(), v = n; stk.pop_back();
      if (ei != -1) {
        dual[E[ei].b] = dual[E[ei].a] + E[ei].k;
        pei[E[ei].b] = (ei ^ 1);
        v = E[ei].b;
      }
      for (auto nei : tree[v]) 
        if (nei != pei[v]) 
          stk.push_back(nei);
    }
  }
  long long Compute() {
    for (int i = 0; i < n; ++i) {
      int ei = AddEdge(n, i, 0, 0);
      tree[n].insert(ei);
      tree[i].insert(ei^1);
    }  
    build();
 
    long long answer = 0;
    ll flow, cost; int ein, eout, ptr = 0;
    const int B = n / 2 + 1;
    for (int it = 0; it < E.size() / B + 1; ++it) { 
      // Find negative cycle (round-robin). 
      cost = 0; ein = -1;
      for (int t = 0; t < B; ++t, (++ptr) %= E.size()) {
        auto& e = E[ptr];
        ll now = dual[e.a] + e.k - dual[e.b];
        if (e.f < e.c && now < cost)
          cost = now, ein = ptr;
      }
      if (ein == -1) continue;

      // Pivot around ein.
      for (int v = E[ein].b; v < n; v = E[pei[v]].b)
        nxt[v] = pei[v];
      for (int v = E[ein].a; v < n; v = E[pei[v]].b)
        nxt[E[pei[v]].b] = (pei[v]^1);
      nxt[E[ein].a] = -1;
      
      int flow = E[ein].c - E[ein].f; eout = ein;
      for (int ei = ein; ei != -1; ei = nxt[E[ei].b]) {
        int res = E[ei].c - E[ei].f;
        if (res < flow) flow = res, eout = ei;
      }
      for (int ei = ein; ei != -1; ei = nxt[E[ei].b]) 
        E[ei].f += flow, E[ei^1].f -= flow;
      
      if (ein != eout) {
        tree[E[ein].a].insert(ein);
        tree[E[ein].b].insert(ein^1);
        tree[E[eout].a].erase(eout);
        tree[E[eout].b].erase(eout^1);
        build(pei[E[eout].a] == eout ? ein : ein^1);
      }
      answer += 1LL * flow * cost;
      it = -1;
    }
    return answer;
  }
};
 
int main() {
  ifstream cin("fmcm.in");
  ofstream cout("fmcm.out");
 
  int n, m, s, t; cin >> n >> m >> s >> t;
  NetworkSimplex NS(n);
  for (int i = 0; i < m; ++i) {
    int a, b, c, k; cin >> a >> b >> c >> k;
    NS.AddEdge(a - 1, b - 1, c, k);
  }
  int ed = NS.AddEdge(t - 1, s - 1, INF, -INF);
  cout << NS.Compute() + 1LL * INF * NS.E[ed].f << endl;
 
  return 0;
}