思路主要是按照紫书上来的,分治算法。先对所有点的y坐标排序,找出y坐标最小的点,设此点为S0。然后计算其他点与此点的连线与x正半轴的夹角,再按夹角的大小给这些点排序,此时,所有点的夹角都在0度到180度之间,所以适合用cos来表示角的大小。S0为蚂蚁时(S0为苹果时同理),则设sumants = 1, sumapple = 0,从夹角最小的点开始(设为S1)(夹角最大的点设为S3),遇到蚂蚁就sumants加1,遇到苹果就sumapple加1,当sumants == sumapple时(设此点为S2),将S0与S2匹配,然后再对[S1, S2)和(S2, S3]区间内的点分别再进行以上步骤。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
typedef struct pos{
int x, y, id, num; //id = 0 is ant, id = 1 is apple tree;
double angle;
}pos;
pos node[300];
int ok[300];
bool cmp1(pos a, pos b)
{
if(a.y == b.y) return a.x < b.x;
else return a.y < b.y;
}
bool cmp2(pos a, pos b)
{
return a.angle > b.angle;
}
double getangle(pos yuan, pos b)
{
double bian = sqrt(pow(b.x - yuan.x, 2) + pow(b.y - yuan.y, 2));
return (b.x - yuan.x)/bian;
}
void match(int first, int last)
{
int t;
if(first >= last) return ; //分治边界
sort(node+first, node+last+1, cmp1);
t = node[first].id;
for(int i = first+1; i <= last; i++)
node[i].angle = getangle(node[first], node[i]);
sort(node+first+1, node+last+1, cmp2);
int sum1 = 1, sum2 = 0;
for(int i = first+1; i <= last; i++)
{
if(node[i].id == t) sum1++;
else sum2++;
if(sum1 == sum2)
{
if(t == 0) ok[node[first].num] = node[i].num;
else ok[node[i].num] = node[first].num;
match(first+1, i-1); //分治
match(i+1, last);
break;
}
}
}
int main()
{
//freopen("ztest.txt","r",stdin);
//freopen("zans.txt","w",stdout);
int n;
int flag = 1;
while(scanf("%d",&n) == 1)
{
if(flag) flag = 0;
if(!flag) printf("\n");
for(int i = 0; i < n; i++)
{
scanf("%d%d", &node[i].x, &node[i].y);
node[i].id = 0;
node[i].num = i+1;
}
for(int i = n; i < 2*n; i++)
{
scanf("%d%d", &node[i].x, &node[i].y);
node[i].id = 1;
node[i].num = i-n+1;
}
match(0, 2*n-1);
for(int i = 1; i <= n; i++)
printf("%d\n", ok[i]);
}
return 0;
}