Cod sursa(job #2771097)

Utilizator retrogradLucian Bicsi retrograd Data 25 august 2021 12:39:19
Problema Cuplaj maxim de cost minim Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.84 kb
#include <bits/stdc++.h>

using namespace std;
using ll = long long;
const int INF = 1e8;

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

  int n;
  vector<int> pei, depth;
  vector<ll> dual;
  vector<Edge> E;
  vector<set<int>> tree;
  
  NetworkSimplex(int n) : 
    n(n), pei(n + 1, -1), depth(n + 1, 0), 
    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 upd(int ei) {
    dual[E[ei].b] = dual[E[ei].a] + E[ei].k;
    pei[E[ei].b] = (ei ^ 1);
    depth[E[ei].b] = 1 + depth[E[ei].a];
    dfs(E[ei].b);
  }
  void dfs(int node) {
    for (auto ei : tree[node]) 
      if (ei != pei[node]) 
        upd(ei);
  }
  template<typename CB> 
  void walk(int a, int b, CB&& cb) {
    if (a == b) return;
    if (depth[a] > depth[b])
      walk(E[pei[a]].b, b, cb), cb(pei[a]^1);
    else 
      cb(pei[b]), walk(a, E[pei[b]].b, cb);
  }
  long long Compute(int x) {
    for (int i = 0; i < n; ++i) {
      int a = n, b = i, c = 1, k = -INF;
      if (i >= x) swap(a, b);
      int ei = AddEdge(a, b, c, k);
      tree[a].insert(ei);
      tree[b].insert(ei^1);
    }  
    dfs(n);

    long long answer = 0;
    ll flow, cost; int ein, eout, ptr = 0;
    const int B = n / 3 + 1;
    for (int z = 0; z < E.size() / B + 1; ++z) { 
      // 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 (cost == 0) continue;
      // Pivot around ein.
      flow = E[ein].c - E[ein].f; eout = ein;
      walk(E[ein].a, E[ein].b, [&](int ei) {
        int res = E[ei].c - E[ei].f;
        if (res < flow) flow = res, eout = ei;
      });
      if (flow) {
        E[ein].f += flow, E[ein^1].f -= flow;
        walk(E[ein].a, E[ein].b, [&](int ei) {
          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);
        upd(pei[E[eout].a] == eout ? ein : ein^1);
      }
      answer += flow * cost;
      z = -1;
    }
    return answer;
  }
};

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

  int n, m, e; cin >> n >> m >> e;
  NetworkSimplex NS(n + m);
  for (int i = 0; i < e; ++i) {
    int a, b, c; cin >> a >> b >> c; --a; --b;
    assert(2 * i == NS.AddEdge(a, b + n, 1, c));
  }

  auto cost = NS.Compute(n);
  int flow = 0;
  while (cost < -INF)
    flow += 1, cost += 2 * INF;
    
  cout << flow << " " << cost << '\n';
  for (int i = 0; i < e; ++i)
    if (NS.E[2 * i].f > 0) 
      cout << i + 1 << " ";
  cout << endl;
  return 0;
}