Cod sursa(job #2436892)

Utilizator AlexPop28Pop Alex-Nicolae AlexPop28 Data 7 iulie 2019 15:38:54
Problema Traseu Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 2.78 kb
#include <bits/stdc++.h>
#define DEBUG(x) cerr << (#x) << ": " << (x) << '\n'

using namespace std;

struct MinCostMaxFlow {
  int source, sink;
  vector<bool> in_q;
  vector<int> q, dist, parent;
  vector<vector<int>> adj, cap, cost;
  MinCostMaxFlow(int n) : 
    source(n), sink(n + 1), in_q(n + 2), dist(n + 2), parent(n + 2), 
      adj(n + 2), cap(n + 2, vector<int>(n + 2)), cost(n + 2, vector<int>(n + 2)) {}
  void AddEdge(int u, int v, int c, int cst) {
    adj[u].emplace_back(v);
    adj[v].emplace_back(u);
    cap[u][v] = c;
    cost[u][v] = cst;
    cost[v][u] = -cst;
  }
  int GetMinCost() {
    int flow_cost = 0;
    while (CanIncreaseFlow()) {
      flow_cost += Augment();
    }
    return flow_cost;
  }
  bool CanIncreaseFlow() {
    fill(dist.begin(), dist.end(), (int)1e9 + 5);
    fill(in_q.begin(), in_q.end(), false);
    fill(parent.begin(), parent.end(), -1);
    q = {source};
    dist[source] = 0;
    for (int i = 0; i < (int)q.size(); ++i) {
      int node = q[i];
      in_q[node] = false;
      for (int &x : adj[node]) {
        if (cap[node][x] > 0 && dist[x] > dist[node] + cost[node][x]) {
          dist[x] = dist[node] + cost[node][x];
          parent[x] = node;
          if (!in_q[x])
            in_q[x] = true, q.emplace_back(x);
        }
      }
    }
    return parent[sink] != -1;
  }
  int Augment() {
    int node = sink, flow = (int)1e9 + 5;
    while (node != source) {
      flow = min(flow, cap[parent[node]][node]);
      node = parent[node];
    }
    node = sink;
    while (node != source) {
      cap[parent[node]][node] -= flow;
      cap[node][parent[node]] += flow;
      node = parent[node];
    }
    return flow * dist[sink];
  }
};

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

  int n, m; cin >> n >> m;
  vector<vector<int>> adj(n), cost(n, vector<int>(n, (int)1e9 + 5));
  vector<int> deg(n);
  int sum_edges = 0;
  for (int i = 0; i < m; ++i) {
    int u, v, c; cin >> u >> v >> c; --u, --v;
    adj[u].emplace_back(v);
    adj[v].emplace_back(u);
    cost[u][v] = c;
    sum_edges += c;
    ++deg[u];
    --deg[v];
  }
  for (int k = 0; k < n; ++k) {
    for (int i = 0; i < n; ++i)
      for (int j = 0; j < n; ++j)
        if (cost[i][j] > cost[i][k] + cost[k][j])
          cost[i][j] = cost[i][k] + cost[k][j];
  }
  vector<int> left, right;
  for (int i = 0; i < n; ++i) {
    if (deg[i] < 0) left.emplace_back(i);
    else if (deg[i] > 0) right.emplace_back(i);
  }
  MinCostMaxFlow g(n);
  int src = n, snk = n + 1;
  for (int &l : left)
    g.AddEdge(src, l, -deg[l], 0);
  for (int &r : right)
    g.AddEdge(r, snk, +deg[r], 0);
  
  for (int &l : left) {
    for (int &r : right)
      if (cost[l][r] != (int)1e9 + 5)
        g.AddEdge(l, r, (int)1e9 + 5, cost[l][r]);
  }
  cout << g.GetMinCost() + sum_edges << endl;
}