二分图匹配的两个主要算法 模板

匈牙利算法

模板题

#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;

const int MAXN = 503;

int n, m;
bool to[MAXN][MAXN];

int xchoice[MAXN];
int ychoice[MAXN];

bool vis[MAXN];

bool match(int x) {
	for (int y = 1; y <= m; y ++) {
		if (to[x][y] == false) continue;
		if (vis[y]) continue;
		vis[y] = true;
		if (ychoice[y] == 0 || match(ychoice[y])) {
			ychoice[y] = x;
			return true;
		}
	}
	return false;
}

int main() {
	int e;
	scanf("%d%d%d", &n, &m, &e);

	for (int i = 0; i < e; i ++) {
		int x, y;
		scanf("%d%d", &x, &y);
		to[x][y] = true;
	}

	int ans = 0;
	for (int i = 1; i <= n; i ++) {
		fill(vis + 1, vis + 1 + m, false);
		if (match(i)) {
			ans ++;
		}
	}
	printf("%d
", ans);
	for (int i = 1; i <= m; i ++)
		xchoice[ychoice[i]] = i;
	for (int i = 1; i <= n; i ++)
		printf("%d ", xchoice[i]);
	printf("
");

	return 0;
}

KM算法

据说KM算法只能用在完备匹配,我想应该不是这样的吧。

这一题就是一个很好的例子。

对不起,我想错了QAQ,KM算法确实是只能用在完备匹配。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;

const int MAXN = 403;
const double INF = 1e100;
const double EPS = 1e-12;

template <class T>
T sqr(const T &x) {
	return x * x;
}

template <class T>
void tension(T &a, const T &b) {
	if (b < a) a = b;
}

template <class T>
void relax(T &a, const T &b) {
	if (b > a) a = b;
}

int n, root;

double dis(int x1, int y1, int x2, int y2) {
	return sqrt(sqr(x1 - x2) + sqr(y1 - y2));
}

double to[MAXN][MAXN * 2];
double A[MAXN], B[MAXN * 2];
double slack[MAXN * 2];
int ychoice[MAXN * 2];
bool visx[MAXN], visy[MAXN * 2];

bool match(int x) {
	visx[x] = true;
	for (int y = 0; y < n << 1; y ++) {
		if (to[x][y] > - EPS) continue;
		if (visy[y]) continue;
		if (abs(to[x][y] - A[x] - B[y]) <= EPS) {
			visy[y] = true;
			if (ychoice[y] == -1 || match(ychoice[y])) {
				ychoice[y] = x;
				return true;
			}
		}
		else {
			tension(slack[y], A[x] + B[y] - to[x][y]);
		}
	}
	return false;
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("input.txt", "r", stdin);
#endif

	scanf("%d", &n);
	static int x[MAXN], y[MAXN];
	int cnt = 0;
	root = 0;
	for (int i = 0; i < n; i ++) {
		scanf("%d%d", x + i, y + i);
		if (y[i] > y[root]) {
			root = i;
			cnt = 1;
		}
		else if (y[i] == y[root]) {
			cnt ++;
		}
	}
	if (cnt != 1) {
		printf("-1
");
		return 0;
	}

	for (int i = 0; i < n; i ++) {
		if (i == root) continue;
		for (int j = 0; j < n; j ++) {
			if (! (y[j] > y[i])) continue;
			to[i][j] = to[i][j + n] = - dis(x[i], y[i], x[j], y[j]);
		}
	}

	fill(A, A + n, - INF);
	fill(ychoice, ychoice + (n << 1), -1);
	for (int i = 0; i < n; i ++)
		for (int j = 0; j < n << 1; j ++) {
			if (to[i][j] > - EPS) continue;
			relax(A[i], to[i][j]);
		}
	for (int i = 0; i < n; i ++) {
		if (i == root) continue;
		while (true) {
			//cerr << i<< endl;
			fill(visx, visx + n, false);
			fill(visy, visy + (n << 1), false);
			fill(slack, slack + (n << 1), INF);
			if (match(i)) break;
			double tmp = INF;
			for (int y = 0; y < n << 1; y ++)
				if (! visy[y]) tension(tmp, slack[y]);
			if (tmp + EPS >= INF) {
				printf("-1
");
				return 0;
			}
			for (int x = 0; x < n; x ++)
				if (visx[x]) A[x] -= tmp;
			for (int y = 0; y < n << 1; y ++)
				if (visy[y]) B[y] += tmp;
		}
	}
	double ans = 0;
	for (int y = 0; y < n << 1; y ++)
		if (ychoice[y] != -1)
			ans += to[ychoice[y]][y];
	printf("%.10lf
", - ans);

	return 0;
}
原文地址:https://www.cnblogs.com/wangck/p/4369596.html