版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/leekerian/article/details/89198042
题解
考虑这样的问题以每个点为圆心做半径为1的圆如图ABC,这些圆相交的相交区域如图斜线标出的,在这个区域里面的点到ABC三个点的圆心的距离都是<=1的所以只要在这个区域里面取点做一个半径为1的圆就能把ABC的圆心给圈起来,所以问题就转化成怎么求覆盖的区域,我们用扫描线的思想,B圆与A圆交于点a,a1与C交于点b,b1,我们令方向为逆时针,这个时候每两个交点都有一个入点一个出点,遇到一个入点我们就+1,遇到出点我们就-1,这样就能表示出被覆盖的次数(参考线段树扫描线求矩形面积),连接AB两圆的圆心,连接a,a1,线段aa1垂直平分AB线段,我们就可以用acos求出角度,然后排序就行了,总复杂度n^2logn
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <math.h>
using namespace std;
const double eps=1e-8;
int sgn(double x)
{
if(fabs(x)<eps) return 0;
if(x<0) return -1;
else return 1;
}
struct point{
double x,y;
int fg;
double at;
point(){}
point(double _x,double _y)
{
x=_x;
y=_y;
}
point operator -(const point &b)const
{
return point(x-b.x,y-b.y);
}
double operator *(const point &b)const
{
return x*b.x+y*b.y;
}
double distance(point p){
return hypot(x - p.x,y - p.y);
}
double len(){
return hypot(x,y);//库函数
}
point trunc(double r){
double l = len();
if(!sgn(l))return *this;
r /= l;
return point(x*r,y*r);
}
double operator ^(const point &b)const{
return x*b.y-y*b.x;
}
point operator +(const point &b)const{
return point(x+b.x,y+b.y);
}
point rotleft(){
return point( - y,x);
}
point rotright(){
return point(y, - x);
}
};
bool cmp1(point a,point b){
double p=a.at,q=b.at;
if(p!=q){
return p<q;
}
return a.fg>b.fg;
}
point p[333];
point p_a[180000];
int main()
{
int n;
while(cin>>n&&n)
{
for(int i=0;i<n;i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
int ans1=1;
for(int i=0;i<n;i++)
{
int cont=0;
for(int j=0;j<n;j++)
{
if(p[i].distance(p[j])>2.0) continue;
if(j==i) continue;
double at1=acos(p[i].distance(p[j])/2.0);
double at2=atan2(p[j].y-p[i].y,p[j].x-p[i].x);
p_a[cont].at=at2-at1;
p_a[cont++].fg=1;
p_a[cont].at=at2+at1;
p_a[cont++].fg=-1;
}
sort(p_a,p_a+cont,cmp1);
int ans2=1;
for(int j=0;j<cont;j++)
{
if(p_a[j].fg==1) ans2++;
else ans2--;
ans1=max(ans1,ans2);
}
}
printf("%d\n",ans1);
}
return 0;
}