二分图_最佳匹配

KM算法求二分图的最佳匹配
1.用于求带权二分图匹配边权值和最大的完备匹配(实际上就是每个左边的点都要匹配上)
2.顶表:一个用于衡量边是否在相等子图内的数值
3.相等子图:点还是原图的点,边是原图边集的子集,包含所有 端点顶标和 = 边权 的边。
4.时间复杂度:一般是0(n^3)

题目:
POJ3565

Ants
Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 8089 Accepted: 2543 Special Judge
Description

Young naturalist Bill studies ants in school. His ants feed on plant-louses that live on apple trees. Each ant colony needs its own apple tree to feed itself.

Bill has a map with coordinates of n ant colonies and n apple trees. He knows that ants travel from their colony to their feeding places and back using chemically tagged routes. The routes cannot intersect each other or ants will get confused and get to the wrong colony or tree, thus spurring a war between colonies.

Bill would like to connect each ant colony to a single apple tree so that all n routes are non-intersecting straight lines. In this problem such connection is always possible. Your task is to write a program that finds such connection.

On this picture ant colonies are denoted by empty circles and apple trees are denoted by filled circles. One possible connection is denoted by lines.

Input

The first line of the input file contains a single integer number n (1 ≤ n ≤ 100) — the number of ant colonies and apple trees. It is followed by n lines describing n ant colonies, followed by n lines describing n apple trees. Each ant colony and apple tree is described by a pair of integer coordinates x and y (−10 000 ≤ x, y ≤ 10 000) on a Cartesian plane. All ant colonies and apple trees occupy distinct points on a plane. No three points are on the same line.

Output

Write to the output file n lines with one integer number on each line. The number written on i-th line denotes the number (from 1 to n) of the apple tree that is connected to the i-th ant colony.

Sample Input

5
-42 58
44 86
7 28
99 34
-13 -59
-47 -44
86 74
68 -75
-68 60
99 -60
Sample Output

4
2
1
5
3

题目大意:
就是给出黑色(蚂蚁群)的点和白色(苹果树)的点的坐标,然后在黑点 与 白点之间连边,然后连接的边不能够交叉。要求按顺序输出(1-n) 的黑点匹配的白色的点的下标。

解题思路:
要求连接的边不能够交叉,即让我们的边的和的长度最小,我们可以让点之间的距离看作这条边的权值,然后我们把每一条边的权值取相反数,用KM算法求最佳匹配,得到的匹配方案就是题中要求的权值最小匹配。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

const int maxn = 105;
const double inf = 1e12;
const double eps = 1e-10;

struct Node {
	double x, y;
}black[maxn], whilt[maxn];

int n;
double delta, w[maxn][maxn], la[maxn], lb[maxn];
bool va[maxn], vb[maxn];
int match[maxn], ans[maxn];

inline double get(Node a, Node b) {
	return -sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

inline bool find(int x) {
	va[x] = true;
	
	for(int y = 1; y <= n; y ++) {
		double tmp = la[x] + lb[y] - w[x][y];
		if(fabs(tmp) < eps) {
			if(!vb[y]) {
				vb[y] = true;
				if(!match[y] || find(match[y])) {
					match[y] = x;
					return true;
				}
			}
		}
	}
	
	return false;
}

inline void KM(void) {
	
	//初始化顶标 
	for(int i = 1; i <= n; i ++) {
		la[i] = -inf;
		
		for(int j = 1; j <= n; j ++) {
			lb[j] = 0;
			la[i] = max(la[i], w[i][j]);
		}
	}
	
	for(int i = 1; i <= n; i ++) 
		while(true) {
			memset(va, false, sizeof va);
			memset(vb, false, sizeof vb);
			
			if(find(i)) break;
			
			delta = inf;
			for(int x = 1; x <= n; x ++)
			if(va[x])
			for(int y = 1; y <= n; y ++)
			if(!vb[y])
			delta = min(delta, la[x] + lb[y] - w[x][y]);
			
			for(int j = 1; j <= n; j ++) {
				if(va[j]) la[j] -= delta;
				if(vb[j]) lb[j] += delta;
			}
		}
		
	for(int i = 1; i <= n; i ++)
		ans[match[i]] = i;
}


int main(void) {
	scanf("%d", &n);
	
	for(int i = 1; i <= n; i ++)
		scanf("%lf%lf", &black[i].x, &black[i].y);
	for(int i = 1; i <= n; i ++)
		scanf("%lf%lf", &whilt[i].x, &whilt[i].y);
		
	for(int i = 1; i <= n; i ++)
		for(int j = 1; j <= n; j ++)
			w[i][j] = get(black[i], whilt[j]); 
			
	KM();
	
	for(int i = 1; i <= n; i ++)
		printf("%d\n", ans[i]);
	
	return 0; 
} 

注意点:
1.由于需要求距离,所以数据类型为 double
2.由于是double 类型,所以判断相等的时候我们需要用到eps, 因为是double,一般为eps = 1e-10.
3.double类型的最大值可以直接初始化为 1e12

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值