MinCostMatching.cc 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. // Min cost bipartite matching via shortest augmenting paths
  2. //
  3. // This is an O(n^3) implementation of a shortest augmenting path
  4. // algorithm for finding min cost perfect matchings in dense
  5. // graphs. In practice, it solves 1000x1000 problems in around 1
  6. // second.
  7. //
  8. // cost[i][j] = cost for pairing left node i with right node j
  9. // Lmate[i] = index of right node that left node i pairs with
  10. // Rmate[j] = index of left node that right node j pairs with
  11. //
  12. // The values in cost[i][j] may be positive or negative. To perform
  13. // maximization, simply negate the cost[][] matrix.
  14. double MinCostMatching(const VVD &cost, VI &Lmate, VI &Rmate) {
  15. int n = int(cost.size());
  16. // construct dual feasible solution
  17. VD u(n);
  18. VD v(n);
  19. for (int i = 0; i < n; i++) {
  20. u[i] = cost[i][0];
  21. for (int j = 1; j < n; j++) u[i] = min(u[i], cost[i][j]);
  22. }
  23. for (int j = 0; j < n; j++) {
  24. v[j] = cost[0][j] - u[0];
  25. for (int i = 1; i < n; i++) v[j] = min(v[j], cost[i][j] - u[i]);
  26. }
  27. // construct primal solution satisfying complementary slackness
  28. Lmate = VI(n, -1);
  29. Rmate = VI(n, -1);
  30. int mated = 0;
  31. for (int i = 0; i < n; i++) {
  32. for (int j = 0; j < n; j++) {
  33. if (Rmate[j] != -1) continue;
  34. if (fabs(cost[i][j] - u[i] - v[j]) < 1e-10) {
  35. Lmate[i] = j;
  36. Rmate[j] = i;
  37. mated++;
  38. break;
  39. }
  40. }
  41. }
  42. VD dist(n);
  43. VI dad(n);
  44. VI seen(n);
  45. // repeat until primal solution is feasible
  46. while (mated < n) {
  47. // find an unmatched left node
  48. int s = 0;
  49. while (Lmate[s] != -1) s++;
  50. // initialize Dijkstra
  51. fill(dad.begin(), dad.end(), -1);
  52. fill(seen.begin(), seen.end(), 0);
  53. for (int k = 0; k < n; k++)
  54. dist[k] = cost[s][k] - u[s] - v[k];
  55. int j = 0;
  56. while (true) {
  57. // find closest
  58. j = -1;
  59. for (int k = 0; k < n; k++) {
  60. if (seen[k]) continue;
  61. if (j == -1 || dist[k] < dist[j]) j = k;
  62. }
  63. seen[j] = 1;
  64. // termination condition
  65. if (Rmate[j] == -1) break;
  66. // relax neighbors
  67. const int i = Rmate[j];
  68. for (int k = 0; k < n; k++) {
  69. if (seen[k]) continue;
  70. const double new_dist = dist[j] + cost[i][k] - u[i] - v[k];
  71. if (dist[k] > new_dist) {
  72. dist[k] = new_dist;
  73. dad[k] = j;
  74. }
  75. }
  76. }
  77. // update dual variables
  78. for (int k = 0; k < n; k++) {
  79. if (k == j || !seen[k]) continue;
  80. const int i = Rmate[k];
  81. v[k] += dist[k] - dist[j];
  82. u[i] -= dist[k] - dist[j];
  83. }
  84. u[s] += dist[j];
  85. // augment along path
  86. while (dad[j] >= 0) {
  87. const int d = dad[j];
  88. Rmate[j] = Rmate[d];
  89. Lmate[Rmate[j]] = j;
  90. j = d;
  91. }
  92. Rmate[j] = s;
  93. Lmate[s] = j;
  94. mated++;
  95. }
  96. double value = 0;
  97. for (int i = 0; i < n; i++)
  98. value += cost[i][Lmate[i]];
  99. return value;
  100. }