Cod sursa(job #1781287)

Utilizator blatulInstitutul de Arta Gastronomica blatul Data 16 octombrie 2016 19:46:17
Problema Cuplaj maxim de cost minim Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 3.79 kb
// 
// Minimum assignment (simplified Jonker-Volgenant)
//
// Description:
//   We are given a cost table of size n times m with n <= m.
//   It finds a minimum cost assignment, i.e.,
//     min sum_{ij} c(i,j) x(i,j)
//     where sum_{i in [n]} x(i,j)  = 1,
//           sum_{j in [m]} x(i,j) <= 1.
//
// Algorithm:
//   Simplified version of Jonker-Volgenant algorithm,
//   which omits a heuristical initialization step.
//
// Complexity:
//   O(n^3).
//   Much faster than the Kuhn-Munkres algorithm.
//
// Note:
//   It finds minimum cost maximal matching.
//   To find the minimum cost non-maximal matching,
//   we add n dummy vertices to the right side.
//
// Verified: 
//   SPOJ 286: Selfish City
//
// References:
//   R. Jonker and A. Volgenant (1987):
//   A shortest augmenting path algorithm for dense and sparse linear assignment problems.
//   Computing, vol.38, no.4, pp.325-340.
//
//   A. Volgenant (1996): 
//   Linear and Semi Assignment Problems: a core oriented approach.
//   Computers and Operations Research, vol.23, pp.917-932.
//   https://github.com/spaghetti-source/algorithm/blob/master/math/assignment.cc

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <cmath>
#include <cstring>
#include <functional>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>

using namespace std;

#define fst first
#define snd second
#define all(c) ((c).begin()), ((c).end())

typedef int value_type;
const value_type inf = 99999999;

void min_assignment(const vector<vector<value_type>> &c, const vector<vector<int>> &edge) {
  const int n = c.size(), m = c[0].size(); // assert(n <= m);
  vector<value_type> v(m), dist(m);        // v: potential
  vector<int> matchL(n,-1), matchR(m,-1);  // matching pairs
  vector<int> index(m), prev(m);
  iota(all(index), 0);

  auto residue = [&](int i, int j) { return c[i][j] - v[j]; };
  for (int f = 0; f < n; ++f) {
    for (int j = 0; j < m; ++j) {
      dist[j] = residue(f, j);
      prev[j] = f;
    }
    value_type w;
    int j, l;
    for (int s = 0, t = 0;;) {
      if (s == t) {
        l = s; w = dist[index[t++]]; 
        for (int k = t; k < m; ++k) {
          j = index[k];
          value_type h = dist[j];
          if (h <= w) {
            if (h < w) { t = s; w = h; }
            index[k] = index[t]; index[t++] = j;
          }
        }
        for (int k = s; k < t; ++k) {
          j = index[k];
          if (matchR[j] < 0) goto aug;
        }
      }
      int q = index[s++], i = matchR[q];
      for (int k = t; k < m; ++k) {
        j = index[k];
        value_type h = residue(i,j) - residue(i,q) + w;
        if (h < dist[j]) { 
          dist[j] = h; prev[j] = i;
          if (h == w) {
            if (matchR[j] < 0) goto aug;
            index[k] = index[t]; index[t++] = j;
          }
        }
      }
    }
aug:for(int k = 0; k < l; ++k) 
      v[index[k]] += dist[index[k]] - w;
    int i;
    do {
      matchR[j] = i = prev[j]; 
      swap(j, matchL[i]);
    } while (i != f);
  }
  value_type opt = 0;
  int flow = 0;
  for (int i = 0; i < n; ++i) {
    if (edge[i][matchL[i]] != -1) {
        flow += 1;
        opt += c[i][matchL[i]]; // (i, matchL[i]) is a solution
    } 
  }
  printf("%d %d\n", flow, opt);
  for (int i = 0; i < n; i += 1) {
      if (edge[i][matchL[i]] != -1) {
          printf("%d ", 1 + edge[i][matchL[i]]);
      }
  }
  putchar('\n');
}

int main() {
    freopen("cmcm.in", "r", stdin);
    freopen("cmcm.out", "w", stdout);

    int n, m, e; scanf("%d %d %d", &n, &m, &e);
    vector<vector<int>> c(n, vector<int>(m+n, 0x3f3f3f3f));
    vector<vector<int>> edge(n, vector<int>(m + n, -1));
    for (int i = 0; i < e; i += 1) {
        int s, t, u; scanf("%d%d%d", &s, &t, &u);
        c[s-1][t-1] = u;
        edge[s - 1][t - 1] = i;
    }
    min_assignment(c, edge);
    return 0;
}