UVa 1411 Ants 巨人和鬼 分治算法

思路主要是按照紫书上来的,分治算法。先对所有点的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;
}
	


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值