计算几何 之 hdu 1077 poj 1981 O(n^2logn)

花了很长时间,终于理解了一些。。。

注意两题输入格式不同。。。O(n^2logn) 

有另一种非常好理解一些的算法,不过时间差点O(n^3),亦能AC  详解+代码,请点击这里 

//  [7/10/2014 Sjm]
// 题目: 用半径为 1 的圆,尽可能多的包含所给点。
 
/***********************************************************************
其实要理解时间复杂度为O(n^2lgn)的算法,首先要知道以下三点:
1)若以一个点 p 为圆心,在半径为 1 的圆内,随便选一个点 p1,皆可捕获到点 p
2)此时,我们把所给的点皆作为圆心,皆做半径为 1 的圆,
3)在圆的交集中,所重叠的最高层数,即:所要求的答案。。。
************************************************************************/
/*
根据以上三点作为基础,理解网上的时间复杂度为O(n^2lgn)的算法,便比较容易了。。
 
关键:将圆的重叠部分转换为弧的重叠部分。(这里可以自己画几个图理解一下)
 
遍历每一个点
	以此点 p 做半径为 1 的圆C,可以获得此圆C与以其他点为圆心所作圆Ci的相交弧(即圆C被圆Ci截取的那段弧),
	存储该相交弧的起点以及终点的极角(并区分它们)到数组;
	对此数组进行排序(若极角相等,端点:始点-->终点;否则,极角:小-->大)
	此时遍历此数组
		1)如果遇到起点,则sum++,表示此时弧可以有重叠 => 可以覆盖到数组此时所代表的点
			在此过程中,若sum > ans, 则 ans = aum (ans 代表所要获得的答案)
		2)如果遇到终点,则sum--,表示此弧已无法重叠 => 已覆盖不到数组此时所代表的点
遍历结束,获得答案。   
 
*/
//hdu 1077
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAX = 305;
const double eps = 1e-6;
int N;
double arr_p[MAX][2];

double Angle[MAX][2];

struct Angle_Jug {
	double angle; // 记录极角
	bool Judge;  // 判断方向:true->相交弧的起点,false->相交弧的终点
};
};

Angle_Jug Aj[MAX];

double Distance(int p1, int p2)
{
	return sqrt((arr_p[p2][0] - arr_p[p1][0])*(arr_p[p2][0] - arr_p[p1][0]) +
		(arr_p[p2][1] - arr_p[p1][1])*(arr_p[p2][1] - arr_p[p1][1]));
}

bool Cmp(const Angle_Jug &ag1, const Angle_Jug &ag2) {
	if (ag1.angle == ag2.angle) {
		return (ag1.Judge > ag2.Judge);
	}
	return ag1.angle < ag2.angle;
}

int Solve(double R) {
	int ans = 1;
	for (int i = 0; i < N; i++) {
		int m = 0;
		for (int j = 0; j < N; j++) {
			double dis = Distance(i, j);
			if ((i == j) || (dis > 2 * R)) { continue; }
			double tep = acos((dis / 2.0) / R);
			double k = atan2(arr_p[j][1] - arr_p[i][1], arr_p[j][0] - arr_p[i][0]);
			Aj[m].angle = k - tep;  Aj[m++].Judge = true;
			Aj[m].angle = k + tep;  Aj[m++].Judge = false;
		}
		sort(Aj, Aj + m, Cmp);
		int sum = 1;
		for (int k = 0; k < m; k++) {
			if (Aj[k].Judge)  {
				sum++;
				ans = (ans > sum) ? ans : sum;
			}
			else { sum--; }
		}
	}
	return ans;
}

int main()
{
	//freopen("input.txt", "r", stdin);
	int T;
	scanf("%d", &T);
	while (T--) {
		scanf("%d", &N);
		for (int i = 0; i < N; i++) {
			scanf("%lf %lf", &arr_p[i][0], &arr_p[i][1]);
		}
		printf("%d\n", Solve(1.0));
	}
}

//poj 1981
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAX = 305;
const double eps = 1e-6;
int N;
double arr_p[MAX][2];

double Angle[MAX][2];

struct Angle_Jug {
	double angle; // 记录极角
	bool Judge;  // 判断方向:true->相交弧的起点,false->相交弧的终点
};

Angle_Jug Aj[MAX];

double Distance(int p1, int p2)
{
	return sqrt((arr_p[p2][0] - arr_p[p1][0])*(arr_p[p2][0] - arr_p[p1][0]) +
		(arr_p[p2][1] - arr_p[p1][1])*(arr_p[p2][1] - arr_p[p1][1]));
}

bool Cmp(const Angle_Jug &ag1, const Angle_Jug &ag2) {
	if (ag1.angle == ag2.angle) {
		return (ag1.Judge > ag2.Judge);
	}
	return ag1.angle < ag2.angle;
}

int Solve(double R) {
	int ans = 1;
	for (int i = 0; i < N; i++) {
		int m = 0;
		for (int j = 0; j < N; j++) {
			double dis = Distance(i, j);
			if ((i == j) || (dis > 2 * R)) { continue; }
			double tep = acos((dis / 2.0) / R);
			double k = atan2(arr_p[j][1] - arr_p[i][1], arr_p[j][0] - arr_p[i][0]);
			Aj[m].angle = k - tep;  Aj[m++].Judge = true;
			Aj[m].angle = k + tep;  Aj[m++].Judge = false;
		}
		sort(Aj, Aj + m, Cmp);
		int sum = 1;
		for (int k = 0; k < m; k++) {
			if (Aj[k].Judge)  {
				sum++;
				ans = (ans > sum) ? ans : sum;
			}
			else { sum--; }
		}
	}
	return ans;
}

int main()
{
	//freopen("input.txt", "r", stdin);
	while (scanf("%d", &N) && N) {
		for (int i = 0; i < N; i++) {
			scanf("%lf %lf", &arr_p[i][0], &arr_p[i][1]);
		}
		printf("%d\n", Solve(1.0));
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值