POJ 3565 Ants (带权二分图最大完备匹配)

题目链接

题目大意:

平面上共有2*N个点,N个是白点,N个是黑点。对于每个白点,找到一个黑点,把二者用线连起来,要求最后所有线段都不想交,求一种方案。

满足总路程之和最小的方案一定不相交

详见 https://blog.csdn.net/lianai911/article/details/44835659

可以建立一个二部图,然后用KM跑最小权匹配,KM跑最小权其实就是把各个边上的权值取反然后跑KM,最后的结果再取反就是最小权。

此题只需要取反后跑一边KM,然后输出匹配边上的点即可

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#define mem(a, b) memset(a, b, sizeof a)
#define eps 1e-8
const int inf = 0x3f3f3f3f;
using namespace std;
const int N = 110;
struct p {
	int x, y;
	p() {

	}
	p(int x, int y) {
		this->x = x;
		this->y = y;
	}
};
p black[N], white[N];
double calculate(p& a, p& b) {
	double dx = ((double)a.x - b.x) * 1.0;
	double dy = ((double)a.y - b.y) * 1.0;
	return sqrt(dx * dx + dy * dy);
}
int n;
int match[N];
double w[N][N];
bool va[N], vb[N];
double la[N], lb[N];
double slack[N];
int res[N];
bool dfs(int x) {
	va[x] = 1;
	for (int i = 1; i <= n; i++) {
		if (!vb[i]) {
			double t = la[x] + lb[i] - w[x][i];
			if (fabs(t) < eps) {
				// ????
				vb[i] = 1;
				if (match[i] == -1 || dfs(match[i])) {
					match[i] = x;
					return 1;
				}
			}
			else if (slack[i] > t)slack[i] = t;
		}
	}
	return 0;
}
void km() {
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			w[i][j] = -calculate(black[i], white[j]);
		}
	}
	mem(match, -1);
	for (int i = 1; i <= n; i++) {
		la[i] = -1e12;
		lb[i] = 0;
		for (int j = 1; j <= n; j++) {
			if (la[i] < w[i][j])la[i] = w[i][j];
		}
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			slack[j] = 1e12;
		}
		while (1) {
			mem(va, 0);
			mem(vb, 0);
			if (dfs(i))break;
			double d = 1e12;
			for (int j = 1; j <= n; j++) {
				if (!vb[j] && d > slack[j])d = slack[j];
			}
			for (int j = 1; j <= n; j++) {
				if (va[j])la[j] -= d;
				if (vb[j])lb[j] += d;
				else slack[j] -= d;
			}
		}
	}
	mem(res, -1);
	double ans = 0;
	for (int i = 1; i <= n; i++) {
		res[match[i]] = i;
	}
	for (int i = 1; i <= n; i++) {
		cout << res[i] << "\n";
	}
}
int main()
{
	ios::sync_with_stdio(0);
	while (cin >> n) {
		for (int i = 1; i <= n; i++) {
			int x, y;
			cin >> x >> y;
			black[i].x = x;
			black[i].y = y;
		}
		for (int j = 1; j <= n; j++) {
			int x, y;
			cin >> x >> y;
			white[j].x = x;
			white[j].y = y;
		}
		km();
	}
	return 0;
}
发布了143 篇原创文章 · 获赞 11 · 访问量 8188

猜你喜欢

转载自blog.csdn.net/weixin_43701790/article/details/104033157
今日推荐