http://poj.org/problem?id=3565
题意:给你n的蚂蚁的坐标和n和苹果的坐标,要你匹配它们,一个要求是它们各自匹配所构成的线段不相交,
题解: 有三角形俩边之和大于第三边可以得到他们连线的所有线段和最小的时候线段一定不会相交。
所以这个题目就转化为二分图最小权匹配,把俩点距离堪称权值,套下KM算法就ok了
#include <iostream>
#include <cstring>
#include <cstdio>
#include<cmath>
using namespace std;
const int MAXN = 115;
double eps = 1e-6;
const double INF = 0x3f3f3f3f;
double dis[MAXN][MAXN];
double ex_bai[MAXN];
double ex_hei[MAXN];
bool vis_hei[MAXN];
bool vis_bai[MAXN];
int match[MAXN];
double slack[MAXN];
int N;
struct node{
int x, y;
}ant[MAXN],apple[MAXN];
double min(double a,double b)
{
return a<b?a:b;
}
double max(double a,double b)
{
return a>b?a:b;
}
bool dfs(int hei)
{
vis_hei[hei] = true;
for (int bai = 1; bai <= N; ++bai) {
if (vis_bai[bai]) continue;
double gap = ex_hei[hei] + ex_bai[bai] - dis[hei][bai];
if (fabs(gap)<=1e-6) { // 如果符合要求
vis_bai[bai] = true;
if (match[bai] == -1 || dfs( match[bai] )) {
match[bai] = hei;
return true;
}
} else {
slack[bai] = min(slack[bai], gap);
}
}
return false;
}
void KM()
{
memset(match, -1, sizeof (match));
memset(ex_bai, 0, sizeof (ex_bai));
for (int i = 1; i <= N; ++i) {
ex_hei[i] = -INF; //最小值这个时候不能是0了,而是-INF
for (int j = 1; j <= N; ++j) {
ex_hei[i] = max(ex_hei[i], dis[i][j]);
}
}
for (int i = 1; i <=N; ++i) {
fill(slack+1, slack + N+1, INF); // 因为要取最小值 初始化为无穷大
while (1) {
memset(vis_hei, false, sizeof vis_hei);
memset(vis_bai, false, sizeof vis_bai);
if (dfs(i)) break; // 找到归宿 退出
// 如果不能找到 就降低期望值
// 最小可降低的期望值
double d = INF;
for (int j = 1; j <=N; ++j)
if (!vis_bai[j]) d = min(d, slack[j]);
for (int j = 1; j <=N; ++j) {
if (vis_hei[j]) ex_hei[j] -= d;
if (vis_bai[j]) ex_bai[j] += d;
else slack[j] -= d;
}
}
}
}
double dist(int i,int j)
{
double x=sqrt((ant[i].x-apple[j].x)*(ant[i].x-apple[j].x)+(ant[i].y-apple[j].y)*(ant[i].y-apple[j].y));
return x;
}
int main()
{
scanf("%d",&N);
for(int i=1;i<=N;i++)
{
scanf("%d %d",&ant[i].x,&ant[i].y);
}
for(int i=1;i<=N;i++)
{
scanf("%d %d",&apple[i].x,&apple[i].y);
}
for(int i=1;i<=N;i++)
{
for(int j=1;j<=N;j++)
{
dis[j][i]=-dist(i,j);//取反
// printf("%.3lf ",dis[j][i]);
}
}
KM();
for(int i=1;i<=N;i++)
{
printf("%d\n",match[i]);
}
return 0;
}