每一次权重矩阵被修改,都关系到一个特定节点,这个节点可能是左边的也可能是右边的,因此我们直接记为 x, 这个节点和某个节点 y 在原来的最优匹配中匹配上了。每一次修改操作,最多让这一对节点 unpair,因此我们只要跑一轮匈牙利算法中的搜索我们就能得到一个新的 match,而根据定理一,新跑出来的 match 是最优的。
以下代码应该为论文 2 作者提交的代码(以下代码为最大化权重版本,原始论文中为最小化 cost)
动态匈牙利算法参考代码
#include <algorithm>#include <cstring>#include <iostream>#include <list>using namespace std;using LL = long long;constexpr LL INF = (LL)1e15;constexpr int MAXV = 105;int N, mateS[MAXV], mateT[MAXV], p[MAXV];LL u[MAXV], v[MAXV], slack[MAXV];LL W[MAXV][MAXV];bool m[MAXV];list<int> Q;void readMatrix() { cin >> N; for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) cin >> W[i][j];}void initHungarian() { memset(mateS, -1, sizeof(mateS)); memset(mateT, -1, sizeof(mateT)); for (int i = 0; i < N; i++) { u[i] = -INF; for (int j = 0; j < N; j++) u[i] = max(u[i], W[i][j]); v[i] = 0; }}void augment(int j) { int i, next; do { i = p[j]; mateT[j] = i; next = mateS[i]; mateS[i] = j; if (next != -1) j = next; } while (next != -1);}LL hungarian() { int nres = 0; for (int i = 0; i < N; i++) if (mateS[i] == -1) nres++; while (nres > 0) { for (int i = 0; i < N; i++) { m[i] = false; p[i] = -1; slack[i] = INF; } bool aug = false; Q.clear(); for (int i = 0; i < N; i++) if (mateS[i] == -1) { Q.push_back(i); break; } do { int i, j; i = Q.front(); Q.pop_front(); m[i] = true; j = 0; while (!aug && j < N) { if (mateS[i] != j) { LL minSlack = u[i] + v[j] - W[i][j]; if (minSlack < slack[j]) { slack[j] = minSlack; p[j] = i; if (slack[j] == 0) { if (mateT[j] == -1) { augment(j); aug = true; nres--; } else Q.push_back(mateT[j]); } } } j++; } if (!aug && Q.size() == 0) { LL minSlack = INF; for (int k = 0; k < N; k++) if (slack[k] > 0) minSlack = min(minSlack, slack[k]); for (int k = 0; k < N; k++) if (m[k]) u[k] -= minSlack; int x = -1; bool X[MAXV]; for (int k = 0; k < N; k++) if (slack[k] == 0) v[k] += minSlack; else { slack[k] -= minSlack; if (slack[k] == 0 && mateT[k] == -1) x = k; if (slack[k] == 0) X[k] = true; else X[k] = false; } if (x == -1) { for (int k = 0; k < N; k++) if (X[k]) Q.push_back(mateT[k]); } else { augment(x); aug = true; nres--; } } } while (!aug); } LL ans = 0; for (int i = 0; i < N; i++) ans += (u[i] + v[i]); return ans;}void dynamicHungarian() { char type[2]; LL w; int i, j; cin >> type; if (type[0] == 'C') { cin >> i >> j >> w; if ((w < W[i][j]) && (mateS[i] == j)) { W[i][j] = w; if (mateS[i] != -1) { mateT[mateS[i]] = -1; mateS[i] = -1; } } else if ((w > W[i][j]) && (u[i] + v[j] < w)) { W[i][j] = w; u[i] = -INF; for (int c = 0; c < N; c++) u[i] = max(u[i], W[i][c] - v[c]); if (mateS[i] != j) { mateT[mateS[i]] = -1; mateS[i] = -1; } } else W[i][j] = w; } else if (type[0] == 'X') { cin >> i; for (int c = 0; c < N; c++) cin >> W[i][c]; if (mateS[i] != -1) { mateT[mateS[i]] = -1; mateS[i] = -1; } u[i] = -INF; for (int c = 0; c < N; c++) u[i] = max(u[i], W[i][c] - v[c]); } else if (type[0] == 'Y') { cin >> j; for (int r = 0; r < N; r++) cin >> W[r][j]; if (mateT[j] != -1) { mateS[mateT[j]] = -1; mateT[j] = -1; } v[j] = -INF; for (int r = 0; r < N; r++) v[j] = max(v[j], W[r][j] - u[r]); } else if (type[0] == 'A') { i = j = N++; u[i] = -INF; for (int c = 0; c < N; c++) u[i] = max(u[i], W[i][c] - v[c]); v[j] = -INF; for (int r = 0; r < N; r++) v[j] = max(v[j], W[r][j] - u[r]); } else if (type[0] == 'Q') cout << hungarian() << '\n';}int main() { cin.tie(nullptr)->sync_with_stdio(false); readMatrix(); initHungarian(); LL ans = hungarian(); int M; cin >> M; while (M--) dynamicHungarian(); return 0;}