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 ≤ xy ≤ 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

题目就是求类似图中实心到空心圆的连线,一一映射,使两两线段不相交。

有一种思路就是一开始让所有点对随意连接,然后让相交的线段进行调整,这里比较好理解,比如AC与BD相交,那么AD与BC就必然不相交了。这样的话需要的调整的次数似乎不是很好计算。

但是可以肯定的是,最终状态必然是两两不相交了。

可以发现上面相交的AC与BD,必然满足AD+BC < AC+BD。这里可以用两次三角形两边之和大于第三边进行证明。这一步让点对里面边的权值和变小了。

于是考虑,逆命题:是否当边AC与BD可以减小成AD与BC时,一定是相交的?

事实证明这个命题是不一定的,但是可以发现当可以减小成AD与BC时,AD和BC一定是不相交的。否则会导致AD+BC > AC+BD。

所以只要能减小边权的和,一定能保证不相交。那么最终状态就变成了边权和最小的状态,也就是最小匹配。可以采用KM算法进行。

似乎是数据问题,不能使用边的平方进行处理。要用double保存边的大小,然后等于0的判断,改成小于eps。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <string>
#define LL long long using namespace std; const int maxN = ;
const double inf = 1e10;
int n;
struct Point
{
double x, y;
}x[maxN], y[maxN];
int nx, ny;
int link[maxN];
double lx[maxN], ly[maxN], slack[maxN], w[maxN][maxN];//link表示和y相接的x值,lx,ly为顶标,nx,ny分别为x点集y点集的个数
bool visx[maxN], visy[maxN]; inline double dis(int i, int j)
{
double ans = (x[i].x-y[j].x)*(x[i].x-y[j].x) + (x[i].y-y[j].y)*(x[i].y-y[j].y);
return -sqrt(ans);
} bool DFS(int x)
{
visx[x] = true;
for (int y = ; y <= ny; y++)
{
if (visy[y])
continue;
double t = lx[x]+ly[y]-w[x][y];
if (fabs(t) < 1e-)
{
visy[y] = true;
if (link[y] == - || DFS(link[y]))
{
link[y] = x;
return true;
}
}
else if (slack[y] > t)//不在相等子图中slack取最小的
slack[y] = t;
}
return false;
} void KM()
{
memset(link, -, sizeof(link));
memset(ly, , sizeof(ly));
for (int i = ; i <= nx; i++)//lx初始化为与它关联边中最大的
for (int j = ; j <= ny; j++)
if (j == || w[i][j] > lx[i])
lx[i] = w[i][j]; for (int x = ; x <= nx; x++)
{
for (int i = ; i <= ny; i++)
slack[i] = inf;
for (;;)
{
memset(visx, false, sizeof(visx));
memset(visy, false, sizeof(visy));
if (DFS(x))//若成功(找到了增广轨),则该点增广完成,进入下一个点的增广
break;//若失败(没有找到增广轨),则需要改变一些点的标号,使得图中可行边的数量增加。
//方法为:将所有在增广轨中(就是在增广过程中遍历到)的X方点的标号全部减去一个常数d,
//所有在增广轨中的Y方点的标号全部加上一个常数d
double d = inf;
for (int i = ; i <= ny; i++)
if (!visy[i] && d > slack[i])
d = slack[i];
for (int i = ; i <= nx; i++)
if (visx[i])
lx[i] -= d;
for (int i = ; i <= ny; i++)//修改顶标后,要把所有不在交错树中的Y顶点的slack值都减去d
if (visy[i])
ly[i] += d;
else
slack[i] -= d;
}
} for (int i = ; i <= n; ++i)
printf("%d\n", link[i]);
} void input()
{
nx = ny = n;
for (int i = ; i <= n; ++i)
scanf("%lf%lf", &y[i].x, &y[i].y);
for (int i = ; i <= n; ++i)
scanf("%lf%lf", &x[i].x, &x[i].y);
for (int i = ; i <= n; ++i)
for (int j = ; j <= n; ++j)
w[i][j] = dis(i, j);
} int main ()
{
//freopen("test.in", "r", stdin);
while (scanf ("%d", &n) != EOF)
{
input();
KM();
}
return ;
}

ACM学习历程—POJ3565 Ants(最佳匹配KM算法)的更多相关文章

  1. 二分图匹配之最佳匹配——KM算法

    今天也大致学了下KM算法,用于求二分图匹配的最佳匹配. 何为最佳?我们能用匈牙利算法对二分图进行最大匹配,但匹配的方式不唯一,如果我们假设每条边有权值,那么一定会存在一个最大权值的匹配情况,但对于KM ...

  2. hdu2255 奔小康赚大钱 二分图最佳匹配--KM算法

    传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子.这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住 ...

  3. POJ3565带权匹配——km算法

    题目:http://poj.org/problem?id=3565 神奇结论:当总边权最小时,任意两条边不相交! 转化为求二分图带权最小匹配. 可以用费用流做.但这里学一下km算法. https:// ...

  4. 二分图最佳匹配KM算法 /// 牛客暑期第五场E

    题目大意: 给定n,有n间宿舍 每间4人 接下来n行 是第一年学校规定的宿舍安排 接下来n行 是第二年学生的宿舍安排意愿 求满足学生意愿的最少交换次数 input 2 1 2 3 4 5 6 7 8 ...

  5. 【HDU 2255】奔小康赚大钱 (最佳二分匹配KM算法)

    奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Subm ...

  6. 训练指南 UVALive - 4043(二分图匹配 + KM算法)

    layout: post title: 训练指南 UVALive - 4043(二分图匹配 + KM算法) author: "luowentaoaa" catalog: true ...

  7. 二分图最大权匹配——KM算法

    前言 这东西虽然我早就学过了,但是最近才发现我以前学的是假的,心中感慨万千(雾),故作此篇. 简介 带权二分图:每条边都有权值的二分图 最大权匹配:使所选边权和最大的匹配 KM算法,全称Kuhn-Mu ...

  8. 二分图 最大权匹配 km算法

    这个算法的本质还是不断的找增广路: KM算法的正确性基于以下定理:若由二分图中所有满足A[i]+B[j]=w[i,j]的边(i,j)构成的子图(称做相等子图)有完备匹配,那么这个完备匹配就是二分图的最 ...

  9. 二分图带权匹配 KM算法与费用流模型建立

    [二分图带权匹配与最佳匹配] 什么是二分图的带权匹配?二分图的带权匹配就是求出一个匹配集合,使得集合中边的权值之和最大或最小.而二分图的最佳匹配则一定为完备匹配,在此基础上,才要求匹配的边权值之和最大 ...

随机推荐

  1. web 文件下载

    response.reset(); response.setContentType("octets/stream"); response.addHeader("Conte ...

  2. elasticsearch从入门到出门-02-简单的CRUD

    操作背景: 电商网站上面的一个商品的增删改查: es 能接受的都是JSON格式的数据 Es 提供了一套简单的集群信息健康监控的api GET /_cat/health?v   epoch      t ...

  3. 被学长教会的高斯消元法Gauss

    昨天学长教了我高斯消元法. 这里用一个栗子来模拟一下Gauss的流程. 真的通俗易懂!这里是洛谷题目链接. 这就是例子 x-2y+3z= 4x-5y+6z= 7x-8y+10z= 先将它转化为矩阵 - ...

  4. HDU 4772 Zhuge Liang&#39;s Password (简单模拟题)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4772 题面: Zhuge Liang's Password Time Limit: 2000/1000 ...

  5. MySql四种隔离级别

    什么是事务 事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消.也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一个都不做. 事务的结束有 ...

  6. linux 7- - watch,free,mpstat,vmstat,iostat,pidstat,df,du

    十八.  和系统运行状况相关的Shell命令:     1.  Linux的实时监测命令(watch):     watch 是一个非常实用的命令,可以帮你实时监测一个命令的运行结果,省得一遍又一遍的 ...

  7. PAT 天梯赛 L2-014. 列车调度 【队列】

    题目链接 https://www.patest.cn/contests/gplt/L2-014 思路 其实 每条火车道 都可以视为一个队列 满足队列的性质 当已经存在的队列 中 的列车序号 都小于 当 ...

  8. 模块化(CommonJs、AMD、CMD、UMD)发展历史与优缺点

    全文主要整理自摘自<Webpack中文指南>(好文,建议直接去看,以下仅对该系列文章中的<历史发展>篇幅进行备份——也整理了点其他内容) 模块化 模块化是老生常谈了,这里不做阐 ...

  9. hadoop-2.0.0-cdh4.6.0、sqoop-1.4.3-cdh4.6.0、mahout-0.7-cdh4.6.0 安装笔记

    1. /etc/profile中环境变量配置: export HADOOP_HOME=/usr/local/hadoop/cdh4. export HADOOP_MAPRED_HOME=${HADOO ...

  10. poj 1419Graph Coloring 【dfs+补图+计算最大团+计算最大独立集 【模板】】

    题目地址:http://poj.org/problem?id=1419 Graph Coloring Time Limit: 1000MS   Memory Limit: 10000K Total S ...