Cod sursa(job #2630349)

Utilizator AlexPop28Pop Alex-Nicolae AlexPop28 Data 25 iunie 2020 13:49:00
Problema Flux maxim de cost minim Scor 70
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.2 kb
#include <bits/stdc++.h>
#define dbg() cerr <<
#define name(x) (#x) << ": " << (x) << ' ' <<

using namespace std;

const int INF = (int)1e9 + 5;

class MinCostMaxFlow {
  struct Edge {
    int to, cap, flow, cost, nxt;
  };

  int n, src, dst;
  pair<int, int> ans;
  vector<Edge> edges;
  vector<int> adj, dist, new_dist, aux, par;

  void addEdge(int from, int to, int cap, int cost) {
    edges.emplace_back(Edge{to, cap, 0, cost, adj[from]});
    adj[from] = edges.size() - 1;
  }

  void BellmanFord() {
    fill(dist.begin(), dist.end(), INF);
    dist[src] = 0;
    vector<bool> in_queue(n);
    vector<int> q = {src};

    for (int it = 0; it < (int)q.size(); ++it) {
      int node = q[it];
      in_queue[node] = false;

      for (int eid = adj[node]; eid != -1; eid = edges[eid].nxt) {
        auto &e = edges[eid];
        if (e.flow == e.cap) continue;
        if (dist[e.to] > dist[node] + e.cost) {
          dist[e.to] = dist[node] + e.cost;
          if (!in_queue[e.to]) {
            in_queue[e.to] = true;
            q.emplace_back(e.to);
          }
        }
      }
    }
  }

  bool Dijkstra() {
    fill(par.begin(), par.end(), -1);
    fill(aux.begin(), aux.end(), INF);
    fill(new_dist.begin(), new_dist.end(), INF);

    static priority_queue<pair<int, int>,
      vector<pair<int, int>>,
        greater<pair<int, int>>> pq;

    pq.emplace(0, src);
    aux[src] = new_dist[src] = 0;
    
    while (!pq.empty()) {
      int cost, node; tie(cost, node) = pq.top(); pq.pop();
      if (cost != aux[node]) continue;

      for (int eid = adj[node]; eid != -1; eid = edges[eid].nxt) {
        auto &e = edges[eid];
        if (e.flow == e.cap) continue;
        int new_cost = e.cost + dist[node] - dist[e.to];

        if (aux[e.to] > aux[node] + new_cost) {
          aux[e.to] = aux[node] + new_cost;
          new_dist[e.to] = new_dist[node] + e.cost;
          pq.emplace(aux[e.to], e.to);
          par[e.to] = eid ^ 1;
        }
      }
    }

    swap(dist, new_dist);
    return par[dst] != -1;
  }

  void IncreaseFlow() {
    int node = dst, flow = INF;
    while (node != src) {
      int e = par[node] ^ 1;
      flow = min(flow, edges[e].cap - edges[e].flow);
      node = edges[par[node]].to;
    }

    ans.first += flow;
    ans.second += flow * dist[dst];

    node = dst;
    while (node != src) {
      int e = par[node] ^ 1;
      edges[e].flow += flow;
      edges[e ^ 1].flow -= flow;
      node = edges[par[node]].to;
    }
  }

public:
  MinCostMaxFlow(int n_) :
    n(n_), adj(n, -1), dist(n), new_dist(n), aux(n), par(n, -1) {}

  void AddEdge(int from, int to, int cap, int cost) {
    addEdge(from, to, cap, cost);
    addEdge(to, from, 0, -cost);
  }

  pair<int, int> Compute(int src, int dst) {
    this->src = src; this->dst = dst;
    BellmanFord();

    ans = {0, 0};
    while (Dijkstra()) {
      IncreaseFlow(); 
    }

    return ans;
  }
};

int main() {
  ifstream cin("fmcm.in");
  ofstream cout("fmcm.out");

  int n, m, src, dst; cin >> n >> m >> src >> dst; --src, --dst;
  MinCostMaxFlow nw(n);
  for (int i = 0; i < m; ++i) {
    int from, to, cap, cost; cin >> from >> to >> cap >> cost; --from, --to;
    nw.AddEdge(from, to, cap, cost);
  }

  cout << nw.Compute(src, dst).second << endl;
}