Cod sursa(job #2770958)

Utilizator retrogradLucian Bicsi retrograd Data 24 august 2021 13:27:19
Problema Flux maxim de cost minim Scor 50
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.65 kb
#include <bits/stdc++.h>

using namespace std;
using ll = long long;
const int INF = 2e9; // greater than sum(e.k), INF * sum(sup) should fit

struct NetworkSimplex {
  struct Edge { int a, b, c, k, f = 0; };

  int n;
  vector<int> sup, pei, depth;
  vector<ll> pi;
  vector<Edge> E;
  
  NetworkSimplex(int n) : 
    n(n), sup(n, 0), pei(n + 1, -1), 
    depth(n + 1, 0), pi(n + 1, 0) {}
  
  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 AddSupply(int x, int d) { sup[x] += d; }

  void build_tree(set<int>& tree_es) {
    static vector<vector<int>> graph;
    static vector<int> q;
    graph.resize(n + 1);
    for (int i = 0; i <= n; ++i)
      graph[i].clear();
    for (auto i : tree_es) {
      auto& e = E[i];
      graph[e.a].push_back(i);
    }
    q.resize(1); q[0] = n; 
    for (int i = 0; i <= n; ++i) {
      int node = q[i];
      for (auto ei : graph[node]) {
        auto& e = E[ei];
        int vec = e.b, k = e.k;
        if (ei == pei[node]) continue;
        pi[vec] = pi[node] + k;
        depth[vec] = 1 + depth[node];
        pei[vec] = (ei ^ 1);
        q.push_back(vec);
      }
    }

    // for (int i = 0; i < n; ++i)
    //   cerr << depth[i] << " ";
    // cerr << endl;
    // for (int i = 0; i < n; ++i)
    //   cerr << pei[i]/2 << " ";
    // cerr << endl;
    // for (int i = 0; i < n; ++i) 
    //   cerr << E[pei[i]].b << " ";
    // cerr << endl;
    // for (int i = 0; i < n; ++i)
    //   cerr << pi[i] << " ";
    // cerr << endl;
  }

  ll Compute() {
    int m = E.size();
    for (int i = 0; i < n; ++i) {
      int a = n, b = i; ll c = sup[i], k = -INF;
      if (c < 0) c *= -1, swap(a, b);
      AddEdge(a, b, c, k);
    }  
    ll answer = 0;
    
    set<int> tree_es;
    for (int i = m; i < m + 2 * n; ++i)
      tree_es.insert(i);

    for (int it = 0; ; ++it) { // pivot
      // cerr << "building tree\n";
      build_tree(tree_es);
      // cerr << "choosing edge: ";

      int ein = -1;
      for (int i = 0; i < (int)E.size(); ++i) {
        auto& e = E[i];
        if (pi[e.a] + e.k - pi[e.b] < 0 && e.f < e.c) {
          ein = i; break;
        }
      }
      // cerr << ein << endl;
      if (ein == -1) break;

      int f = E[ein].c - E[ein].f;
      pair<int, int> eout = {f, ein};
      auto walk = [&](int ei, int phase) {
        auto nxt = [&](int ei, int dir) {
          ei ^= dir;
          int res = E[ei].c - E[ei].f;
          if (phase == 0) {
            f = min(f, res);
            eout = min(eout, make_pair(res, ei));
          } else {
            E[ei].f += f, E[ei^1].f -= f;
            answer += 1LL * f * E[ei].k;
          }
          ei ^= dir;
          return E[ei].b;
        };
        nxt(ei, 0);
        int a = E[ei].a, b = E[ei].b;
        while (a != b) {
          // cerr << "a: " << a << "b: " << b << " depth: " << depth[a] << " " << depth[b] << endl;
          if (depth[a] > depth[b]) 
            a = nxt(pei[a], 1);
          else b = nxt(pei[b], 0);
        }
      };
      for (int phase : {0, 1}) 
        walk(ein, phase);
      // cerr << "iter=" << it << " flow=" << f << " cost=" << answer << endl; 
      tree_es.insert(ein); tree_es.insert(ein^1);
      tree_es.erase(eout.second); tree_es.erase(eout.second^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;
}