欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

E. Fruit Slicer--计算几何+两圆公切线

程序员文章站 2022-04-01 20:43:00
...

https://open.kattis.com/problems/fruitslicer

很明显,直线是两圆公切线的时候,经过的圆最多,而n只有100,公切线最多4条,只需要(n^2)暴力枚举两圆公切线,然后再(n)得到公切线经过圆的数目,最后取max即可。复杂度O(n^3)级别 

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;


const double eps = 1e-6;
const double PI = acos(-1.0);
int sgn(double x){
    if(fabs(x) < eps)return 0;
    if(x < 0)return-1;
    else return 1;
}
double sqr(double x){return x*x;}
struct Point{
    double x, y;
Point(){}
    Point(double _x,double _y){
        x = _x;
        y = _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);
    }
};
  
struct Line{
    Point s,e;
Line(){}
    Line(Point _s,Point _e){
        s = _s;
        e = _e;
    }
      
    //求线段长度
    double length(){
        return s.distance(e);
    }
   
    double dispointtoline(Point p){
        return fabs((p-s)^(e-s))/length();
    }
};
struct Circle{
    Point p;
    double r;
Circle(){}
    Circle(Point _p,double _r){
        p = _p;
        r = _r;
    }
    // 过一点知道角度和距离 求另一点 
    Point GP(double b) { 
        return Point(p.x + cos(b)*r, p.y+sin(b)*r);
    }
      
    int relationline(Line v){
        double dst = v.dispointtoline(p);
        if(sgn(dst-r) < 0)return 2;
        else if(sgn(dst-r) == 0)return 1;
        return 0;
    }
}CC[200],C1,C2;;

const double Pi=acos(-1.0);

struct Intersect{
    Point P[2];
   bool operator <(const Intersect &rtm) const{
       return sgn(P[0].x-rtm.P[0].x)<0||(sgn(P[0].x-rtm.P[0].x)==0&&sgn(P[0].y-rtm.P[0].y)<0);
   }
}ANS[7];

typedef Point Vector;

double GPA(Vector A){//Get_Polar_Angle
    return atan2(A.y,A.x);
}
double GL(Vector A){//Get_Length
   return sqrt(A*A);
}
//求公切线,这个模板都没问题
int GCCI(Circle A,Circle B){//Get_Circle_Circle_Intersection
    int cnt=0,a=0,b=1;
    if(A.r<B.r) swap(A,B),swap(a,b);
    Vector u=B.p-A.p;
    double d=GL(u),rdec=A.r-B.r,radd=A.r+B.r;
    if(sgn(d-rdec)<0) return 0;                 //内含
    if(sgn(d)==0&&A.r==B.r) {
        ANS[1].P[a] = A.p;
        ANS[1].P[b] = A.GP(PI);
        return 1;             //重合,无线多,原本返回-1,但这题特殊
                             
                            }
    double base=GPA(u);
    if(sgn(d-rdec)==0){                            //内切
        ANS[++cnt].P[a]=A.GP(base); ANS[cnt].P[b]=B.GP(base);
        return cnt;
    }
    double da=acos((A.r-B.r)/d);                    //2条外公切线
    ANS[++cnt].P[a]=A.GP(base+da); ANS[cnt].P[b]=B.GP(base+da);
    ANS[++cnt].P[a]=A.GP(base-da); ANS[cnt].P[b]=B.GP(base-da);
    if(sgn(d-radd)==0){                            //1条内公切线
        ANS[++cnt].P[a]=A.GP(base); ANS[cnt].P[b]=B.GP(base+Pi);
    }
    else if(sgn(d-radd)>0){                     //2条内公切线
        da=acos((A.r+B.r)/d);
        ANS[++cnt].P[a]=A.GP(base+da); ANS[cnt].P[b]=B.GP(base+da+Pi);
        ANS[++cnt].P[a]=A.GP(base-da); ANS[cnt].P[b]=B.GP(base-da+Pi);
    }
    return cnt;
}

int main(){
    int cnt;
    int n;
    int aans=0;
    int last_ans=0;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
    	scanf("%lf %lf", &CC[i].p.x, &CC[i].p.y);
    	CC[i].r=1;
    }
    bool flag=true;
   
	{
		for(int i=0;i<n;i++)
	    {
	    	for(int j=i+1;j<n;j++)
	    	{
	    		C1=CC[i];C2=CC[j];
		        cnt=GCCI(C1,C2);
		        if(cnt<=0) continue;
		        sort(ANS+1,ANS+cnt+1);
		        for(int i=1;i<=cnt;i++)
				{//ans.p切点 	
					aans=0;
		        	Line temp = Line(ANS[i].P[0],ANS[i].P[1]);
					int res;
					Point xx,yy;
		        	for(int k=0;k<n;k++)
		        	{
		        		res=CC[k].relationline(temp);
		        		if(res)aans++;
		        	}
		        	last_ans=max(last_ans,aans);
		        }		
	    	}
	    }
	    if(n == 1) last_ans = 1;
	    cout<<last_ans<<endl;
	}


         
    return 0;
}

 

相关标签: ACM