Boundary(计算几何)
程序员文章站
2022-03-02 10:58:00
...
圆上的一个点(原点)已经确定了,我们枚举一下另一个定点 P,然后枚举点 A ,此时不共线的三点已经可以确定一个圆了,换句话说,三个点就可以确定下来圆心的位置了,当点 P 和点 O 都确定下来后,枚举点 A 所得到的所有圆心的众数再加一,就是以此圆心做圆后可以经过的点的个数,利用map维护最大值就是答案了,找圆心的任务直接交给模板就好了。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
// `计算几何模板`
const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxp = 1010;
//`Compares a double to zero`
int sgn(double x){
if(fabs(x) < eps)return 0;
if(x < 0)return -1;
else return 1;
}
//square of a double
inline double sqr(double x){return x*x;}
/*
* Point
* Point() - Empty constructor
* Point(double _x,double _y) - constructor
* input() - double input
* output() - %.2f output
* operator == - compares x and y
* operator < - compares first by x, then by y
* operator - - return new Point after subtracting curresponging x and y
* operator ^ - cross product of 2d points
* operator * - dot product
* len() - gives length from origin
* len2() - gives square of length from origin
* distance(Point p) - gives distance from p
* operator + Point b - returns new Point after adding curresponging x and y
* operator * double k - returns new Point after multiplieing x and y by k
* operator / double k - returns new Point after divideing x and y by k
* rad(Point a,Point b)- returns the angle of Point a and Point b from this Point
* trunc(double r) - return Point that if truncated the distance from center to r
* rotleft() - returns 90 degree ccw rotated point
* rotright() - returns 90 degree cw rotated point
* rotate(Point p,double angle) - returns Point after rotateing the Point centering at p by angle radian ccw
*/
struct Point{
double x,y;
Point(){}
Point(double _x,double _y){
x = _x;
y = _y;
}
void input(){
scanf("%lf%lf",&x,&y);
}
void output(){
printf("%.2f %.2f\n",x,y);
}
bool operator == (Point b)const{
return sgn(x-b.x) == 0 && sgn(y-b.y) == 0;
}
bool operator < (Point b)const{
return sgn(x-b.x)== 0?sgn(y-b.y)<0:x<b.x;
}
Point operator -(const Point &b)const{
return Point(x-b.x,y-b.y);
}
//叉积
double operator ^(const Point &b)const{
return x*b.y - y*b.x;
}
//点积
double operator *(const Point &b)const{
return x*b.x + y*b.y;
}
//返回长度
double len(){
return hypot(x,y);//库函数
}
//返回长度的平方
double len2(){
return x*x + y*y;
}
//返回两点的距离
double distance(Point p){
return hypot(x-p.x,y-p.y);
}
Point operator +(const Point &b)const{
return Point(x+b.x,y+b.y);
}
Point operator *(const double &k)const{
return Point(x*k,y*k);
}
Point operator /(const double &k)const{
return Point(x/k,y/k);
}
//`计算pa 和 pb 的夹角`
//`就是求这个点看a,b 所成的夹角`
//`测试 LightOJ1203`
double rad(Point a,Point b){
Point p = *this;
return fabs(atan2( fabs((a-p)^(b-p)),(a-p)*(b-p) ));
}
//`化为长度为r的向量`
Point trunc(double r){
double l = len();
if(!sgn(l))return *this;
r /= l;
return Point(x*r,y*r);
}
//`逆时针旋转90度`
Point rotleft(){
return Point(-y,x);
}
//`顺时针旋转90度`
Point rotright(){
return Point(y,-x);
}
//`绕着p点逆时针旋转angle`
Point rotate(Point p,double angle){
Point v = (*this) - p;
double c = cos(angle), s = sin(angle);
return Point(p.x + v.x*c - v.y*s,p.y + v.x*s + v.y*c);
}
}p[2010];
/*
* Stores two points
* Line() - Empty constructor
* Line(Point _s,Point _e) - Line through _s and _e
* operator == - checks if two points are same
* Line(Point p,double angle) - one end p , another end at angle degree
* Line(double a,double b,double c) - Line of equation ax + by + c = 0
* input() - inputs s and e
* adjust() - orders in such a way that s < e
* length() - distance of se
* angle() - return 0 <= angle < pi
* relation(Point p) - 3 if point is on line
* 1 if point on the left of line
* 2 if point on the right of line
* pointonseg(double p) - return true if point on segment
* parallel(Line v) - return true if they are parallel
* segcrossseg(Line v) - returns 0 if does not intersect
* returns 1 if non-standard intersection
* returns 2 if intersects
* linecrossseg(Line v) - line and seg
* linecrossline(Line v) - 0 if parallel
* 1 if coincides
* 2 if intersects
* crosspoint(Line v) - returns intersection point
* dispointtoline(Point p) - distance from point p to the line
* dispointtoseg(Point p) - distance from p to the segment
* dissegtoseg(Line v) - distance of two segment
* lineprog(Point p) - returns projected point p on se line
* symmetrypoint(Point p) - returns reflection point of p over se
*
*/
struct Line{
Point s,e;
Line(){}
Line(Point _s,Point _e){
s = _s;
e = _e;
}
bool operator ==(Line v){
return (s == v.s)&&(e == v.e);
}
//`根据一个点和倾斜角angle确定直线,0<=angle<pi`
Line(Point p,double angle){
s = p;
if(sgn(angle-pi/2) == 0){
e = (s + Point(0,1));
}
else{
e = (s + Point(1,tan(angle)));
}
}
//ax+by+c=0
Line(double a,double b,double c){
if(sgn(a) == 0){
s = Point(0,-c/b);
e = Point(1,-c/b);
}
else if(sgn(b) == 0){
s = Point(-c/a,0);
e = Point(-c/a,1);
}
else{
s = Point(0,-c/b);
e = Point(1,(-c-a)/b);
}
}
void input(){
s.input();
e.input();
}
void adjust(){
if(e < s)swap(s,e);
}
//求线段长度
double length(){
return s.distance(e);
}
//`返回直线倾斜角 0<=angle<pi`
double angle(){
double k = atan2(e.y-s.y,e.x-s.x);
if(sgn(k) < 0)k += pi;
if(sgn(k-pi) == 0)k -= pi;
return k;
}
//`点和直线关系`
//`1 在左侧`
//`2 在右侧`
//`3 在直线上`
int relation(Point p){
int c = sgn((p-s)^(e-s));
if(c < 0)return 1;
else if(c > 0)return 2;
else return 3;
}
// 点在线段上的判断
bool pointonseg(Point p){
return sgn((p-s)^(e-s)) == 0 && sgn((p-s)*(p-e)) <= 0;
}
//`两向量平行(对应直线平行或重合)`
bool parallel(Line v){
return sgn((e-s)^(v.e-v.s)) == 0;
}
//`两线段相交判断`
//`2 规范相交`
//`1 非规范相交`
//`0 不相交`
int segcrossseg(Line v){
int d1 = sgn((e-s)^(v.s-s));
int d2 = sgn((e-s)^(v.e-s));
int d3 = sgn((v.e-v.s)^(s-v.s));
int d4 = sgn((v.e-v.s)^(e-v.s));
if( (d1^d2)==-2 && (d3^d4)==-2 )return 2;
return (d1==0 && sgn((v.s-s)*(v.s-e))<=0) ||
(d2==0 && sgn((v.e-s)*(v.e-e))<=0) ||
(d3==0 && sgn((s-v.s)*(s-v.e))<=0) ||
(d4==0 && sgn((e-v.s)*(e-v.e))<=0);
}
//`直线和线段相交判断`
//`-*this line -v seg`
//`2 规范相交`
//`1 非规范相交`
//`0 不相交`
int linecrossseg(Line v){
int d1 = sgn((e-s)^(v.s-s));
int d2 = sgn((e-s)^(v.e-s));
if((d1^d2)==-2) return 2;
return (d1==0||d2==0);
}
//`两直线关系`
//`0 平行`
//`1 重合`
//`2 相交`
int linecrossline(Line v){
if((*this).parallel(v))
return v.relation(s)==3;
return 2;
}
//`求两直线的交点`
//`要保证两直线不平行或重合`
Point crosspoint(Line v){
double a1 = (v.e-v.s)^(s-v.s);
double a2 = (v.e-v.s)^(e-v.s);
return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
}
//点到直线的距离
double dispointtoline(Point p){
return fabs((p-s)^(e-s))/length();
}
//点到线段的距离
double dispointtoseg(Point p){
if(sgn((p-s)*(e-s))<0 || sgn((p-e)*(s-e))<0)
return min(p.distance(s),p.distance(e));
return dispointtoline(p);
}
//`返回线段到线段的距离`
//`前提是两线段不相交,相交距离就是0了`
double dissegtoseg(Line v){
return min(min(dispointtoseg(v.s),dispointtoseg(v.e)),min(v.dispointtoseg(s),v.dispointtoseg(e)));
}
//`返回点p在直线上的投影`
Point lineprog(Point p){
return s + ( ((e-s)*((e-s)*(p-s)))/((e-s).len2()) );
}
//`返回点p关于直线的对称点`
Point symmetrypoint(Point p){
Point q = lineprog(p);
return Point(2*q.x-p.x,2*q.y-p.y);
}
};
//圆
struct circle{
Point p;//圆心
double r;//半径
circle(){}
circle(Point _p,double _r){
p = _p;
r = _r;
}
circle(double x,double y,double _r){
p = Point(x,y);
r = _r;
}
//`三角形的外接圆`
//`需要Point的+ / rotate() 以及Line的crosspoint()`
//`利用两条边的中垂线得到圆心`
//`测试:UVA12304`
circle(Point a,Point b,Point c){
Line u = Line((a+b)/2,((a+b)/2)+((b-a).rotleft()));
Line v = Line((b+c)/2,((b+c)/2)+((c-b).rotleft()));
p = u.crosspoint(v);
r = p.distance(a);
}
//`三角形的内切圆`
//`参数bool t没有作用,只是为了和上面外接圆函数区别`
//`测试:UVA12304`
circle(Point a,Point b,Point c,bool t){
Line u,v;
double m = atan2(b.y-a.y,b.x-a.x), n = atan2(c.y-a.y,c.x-a.x);
u.s = a;
u.e = u.s + Point(cos((n+m)/2),sin((n+m)/2));
v.s = b;
m = atan2(a.y-b.y,a.x-b.x) , n = atan2(c.y-b.y,c.x-b.x);
v.e = v.s + Point(cos((n+m)/2),sin((n+m)/2));
p = u.crosspoint(v);
r = Line(a,b).dispointtoseg(p);
}
//输入
void input(){
p.input();
scanf("%lf",&r);
}
//输出
void output(){
printf("%.2lf %.2lf %.2lf\n",p.x,p.y,r);
}
bool operator == (circle v){
return (p==v.p) && sgn(r-v.r)==0;
}
bool operator < (circle v)const{
return ((p<v.p)||((p==v.p)&&sgn(r-v.r)<0));
}
//面积
double area(){
return pi*r*r;
}
//周长
double circumference(){
return 2*pi*r;
}
};
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
p[i].input();
}
if(n<=1)
{
printf("%d\n",n);
return 0;
}
int ans=1;
for(int i=1;i<=n;i++)
{
map<Point,int> mp;
for(int j=i+1;j<=n;j++)
{
if(Line(p[i],p[j]).parallel(Line(p[i],Point(0,0))))continue;//三点可能共线,判断三点共线不要用角度,用两条直线平行
circle c=circle(p[i],p[j],Point(0,0));
mp[c.p]++;
ans=max(ans,mp[c.p]+1);
}
}
printf("%d\n",ans);
}