MinCostMatching.cc 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  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. typedef vector<double> VD;
  15. typedef vector<VD> VVD;
  16. typedef vector<int> VI;
  17. double MinCostMatching(const VVD &cost, VI &Lmate, VI &Rmate) {
  18. int n = int(cost.size());
  19. // construct dual feasible solution
  20. VD u(n);
  21. VD v(n);
  22. for (int i = 0; i < n; i++) {
  23. u[i] = cost[i][0];
  24. for (int j = 1; j < n; j++) u[i] = min(u[i], cost[i][j]);
  25. }
  26. for (int j = 0; j < n; j++) {
  27. v[j] = cost[0][j] - u[0];
  28. for (int i = 1; i < n; i++) v[j] = min(v[j], cost[i][j] - u[i]);
  29. }
  30. // construct primal solution satisfying complementary slackness
  31. Lmate = VI(n, -1);
  32. Rmate = VI(n, -1);
  33. int mated = 0;
  34. for (int i = 0; i < n; i++) {
  35. for (int j = 0; j < n; j++) {
  36. if (Rmate[j] != -1) continue;
  37. if (fabs(cost[i][j] - u[i] - v[j]) < 1e-10) {
  38. Lmate[i] = j;
  39. Rmate[j] = i;
  40. mated++;
  41. break;
  42. }
  43. }
  44. }
  45. VD dist(n);
  46. VI dad(n);
  47. VI seen(n);
  48. // repeat until primal solution is feasible
  49. while (mated < n) {
  50. // find an unmatched left node
  51. int s = 0;
  52. while (Lmate[s] != -1) s++;
  53. // initialize Dijkstra
  54. fill(dad.begin(), dad.end(), -1);
  55. fill(seen.begin(), seen.end(), 0);
  56. for (int k = 0; k < n; k++)
  57. dist[k] = cost[s][k] - u[s] - v[k];
  58. int j = 0;
  59. while (true) {
  60. // find closest
  61. j = -1;
  62. for (int k = 0; k < n; k++) {
  63. if (seen[k]) continue;
  64. if (j == -1 || dist[k] < dist[j]) j = k;
  65. }
  66. seen[j] = 1;
  67. // termination condition
  68. if (Rmate[j] == -1) break;
  69. // relax neighbors
  70. const int i = Rmate[j];
  71. for (int k = 0; k < n; k++) {
  72. if (seen[k]) continue;
  73. const double new_dist = dist[j] + cost[i][k] - u[i] - v[k];
  74. if (dist[k] > new_dist) {
  75. dist[k] = new_dist;
  76. dad[k] = j;
  77. }
  78. }
  79. }
  80. // update dual variables
  81. for (int k = 0; k < n; k++) {
  82. if (k == j || !seen[k]) continue;
  83. const int i = Rmate[k];
  84. v[k] += dist[k] - dist[j];
  85. u[i] -= dist[k] - dist[j];
  86. }
  87. u[s] += dist[j];
  88. // augment along path
  89. while (dad[j] >= 0) {
  90. const int d = dad[j];
  91. Rmate[j] = Rmate[d];
  92. Lmate[Rmate[j]] = j;
  93. j = d;
  94. }
  95. Rmate[j] = s;
  96. Lmate[s] = j;
  97. mated++;
  98. }
  99. double value = 0;
  100. for (int i = 0; i < n; i++)
  101. value += cost[i][Lmate[i]];
  102. return value;
  103. }