花了很长时间,终于理解了一些。。。
注意两题输入格式不同。。。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;
}