1. 程式人生 > 實用技巧 >KM求每個大小的匹配的最優解 模板

KM求每個大小的匹配的最優解 模板

參考cz_xuyixuan的營員交流。

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

int tp;

const int N = 505;

int n, Q;
int a[N][N];

const int inf = 2e9;

ll ans[N];

namespace km {

int nl, nr;
int visx[N], visy[N], chox[N], choy[N], fr[N];
int sla[N], x[N], y[N];

void work() {
	fo(i, 1, nl) x[i] = inf;
	fo(s, 1, n) {
		fo(i, 1, nr) visy[i] = fr[i] = 0, sla[i] = inf;
		fo(i, 1, nl) {
			if(!chox[i]) {
				visx[i] = 1;
				fo(j, 1, nr) {
					ll v = x[i] + y[j] - a[i][j];
					if(v < sla[j]) {
						sla[j] = v;
						fr[j] = i;
					}
				}
			} else visx[i] = 0;
		}
		int found = 0;
		while(!found) {
			int mi = inf;
			fo(i, 1, nr) if(!visy[i]) mi = min(mi, sla[i]);
			fo(i, 1, nl) if(visx[i]) x[i] -= mi;
			fo(i, 1, nr) if(visy[i]) y[i] += mi; else sla[i] -= mi;
			fo(i, 1, nr) if(!visy[i] && sla[i] == 0) {
				visy[i] = 1;
				if(!choy[i]) {
					found = 1;
					int p = fr[i], q = i;
					while(q) {
						int nq = chox[p];
						chox[p] = q, choy[q] = p;
						q = nq, p = fr[q];
					}
					break;
				} else {
					int p = choy[i];
					visx[p] = 1;
					fo(j, 1, nr) {
						int v = x[p] + y[j] - a[p][j];
						if(v < sla[j]) {
							sla[j] = v;
							fr[j] = p;
						}
					}
				}
			}
		}
		ans[s] = 0;
		fo(i, 1, nl) if(chox[i])
			ans[s] += a[i][chox[i]];
	}
}

}
int main() {
	freopen("allocation.in", "r", stdin);
	freopen("allocation.out", "w", stdout);
	scanf("%d", &tp);
	scanf("%d %d", &n, &Q);
	fo(i, 1, n) {
		fo(j, 1, n) scanf("%d", &a[i][j]);
	}
	km :: nl = km :: nr = n;
	km :: work();
	fo(ii, 1, Q) {
		int c; scanf("%d", &c);
		c = min(c, n);
		pp("%lld.0\n", ans[c]);
	}
}