E. Fruit Slicer--計算幾何+兩圓公切線

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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章