计算几何入门。。。

计算几何入门

入门题目:1490 : Master ☆ Spark

超级无敌刁难压轴题,浪费了我很多时间(还是没做出来);

#include <bits/stdc++.h>

using namespace std;

const double eps=1e-8;
const double PI=acos(-1);

int sgn(double number,double eps=1e-8)
{
    if(fabs(number)<eps){
        return 0;
    }else{
        return number>0?1:-1;
    }
}

class Point;
double Cross(Point p1,Point p2);
double Dot(Point p1,Point p2);
double Getlen(Point var);
double Getlen2(Point var);

struct Point{
    //向量
    double x;
    double y;
    double angle;
    Point(double xx=0,double yy=0):x(xx),y(yy){
        double X=acos(xx/sqrt(xx*xx+yy*yy));
        double Y=asin(yy/sqrt(xx*xx+yy*yy));
    	if(xx){
	        if( Y>0 )angle=X;
	        else angle=2*PI-X;
		}else{
			if( Y>0 )angle=X;
	        else angle=2*PI-X;
		}
    }

    void operator+=(Point p){x+=p.x,y+=p.y;}
    void operator-=(Point p){x-=p.x,y-=p.y;}
    void operator*=(int factor){x*=factor,y*=factor;}
    void operator/=(int factor){x/=factor,y/=factor;}
    void operator*=(double factor){x*=factor,y*=factor;}
    void operator/=(double factor){x/=factor,y/=factor;}
    friend Point operator+(Point p1,Point p2){return Point(p1.x+p2.x,p1.y+p2.y);}
    friend Point operator-(Point p1,Point p2){return Point(p1.x-p2.x,p1.y-p2.y);}
    friend Point operator*(Point p1,double factor){return Point(p1.x*factor,p1.y*factor);}
    friend Point operator*(double factor,Point p1){return Point(p1.x*factor,p1.y*factor);}
    friend Point operator/(Point p1,double factor){return Point(p1.x/factor,p1.y/factor);}

    Point Rotate(double rad){return Point(x*cos(rad)-y*sin(rad),x*sin(rad)+y*cos(rad));}
    Point Normal(){return Point(-y,x);}

    friend double Cross(Point p1,Point p2){return p1.x*p2.y-p2.x*p1.y;}
    friend double Dot(Point p1,Point p2){return p1.x*p2.x+p2.y*p1.y;}
    friend double Getlen(Point var){return sqrt(Dot(var,var));}
    friend double Getlen2(Point var){return Dot(var,var);}

    friend Getangle(Point var,Point STD){
        double X=acos(Dot(STD,var)/Getlen(var));
        double Y=asin(Cross(STD,var)/Getlen(var));
        if( Y>0 ){
            return X;
        }else{
            return 2*PI-X;
        }
    }

    bool operator<(const Point&x)const{
        return angle<x.angle;
    }
};

bool OnSegment(Point p, Point a1, Point a2){
    return sgn(Cross(a1-p, a2-p)) == 0 && sgn(Dot(a1-p, a2-p)) < 0;
}

bool isCross(Point& a ,Point& b ,Point& c ,Point&d);
Point Cross_Point(Point& a ,Point& b ,Point& c ,Point&d);

struct Line{
    Point p1;
    Point p2;
    Point Dir;
    double A,B,C;
    Line(){;}
    Line(Point p1,Point p2):p1(p1),p2(p2){A=p1.y-p2.y,B=p2.x-p1.x,C=Cross(p1,p2);if(p1.x>p2.x)swap(p1,p2);Dir=p2-p1;}
    Line(double a,double b,double c){
        if( !sgn(a) ){
            p1=Point(0,-c/b);
            p2=Point(1,-c/b);
        }else if( !sgn(b) ){
            p1=Point(-c/a,0);
            p2=Point(-c/a,1);
        }else{
            p1=Point(0,-c/b);
            p2=Point(1,-(-c-a)/b);
        }
    }

    Line Parallel_move(double w){
		Point temp=Dir.Normal()/Getlen(Dir);
		return Line( p1+w*temp,p2+w*temp );
	}
//    Line Verdict_move(double w){Point temp=Dir.Normal()/Getlen(Dir.Normal()); return Line( p1+w*temp,p2+w*temp );}

    friend bool isCross(Point& a ,Point& b ,Point& c ,Point&d){
        double c1=Cross(b-a,c-a),c2=Cross(b-a,d-a);
        double d1=Cross(d-c,a-c),d2=Cross(d-c,b-c);
        if( !sgn(c1) || !sgn(c2) || !sgn(d1) || !sgn(d2) ){
	        bool f1 = OnSegment(c, a, b);
	        bool f2 = OnSegment(d, a, b);
	        bool f3 = OnSegment(a, c, d);	
	        bool f4 = OnSegment(b, c, d);
	        bool f = (f1|f2|f3|f4);
	        return f;
	    }else{
        	return sgn(c1)*sgn(c2)<0 && sgn(d1)*sgn(d2)<0; 
		}
    }
    friend bool isCross(Line& l1,Line& l2){
        return isCross(l1.p1,l1.p2,l2.p1,l2.p2);
    }

    friend Point Cross_Point(Point& a ,Point& b ,Point& c ,Point&d){
        double s1=Cross(b-a,c-a);
        double s2=Cross(b-a,d-a);
        if( sgn(s1-s2) )
            return Point( (c.x*s2-d.x*s1),(c.y*s2-d.y*s1) )/(s2-s1);
        else
            return Point(DBL_MAX,DBL_MAX);
    }

    friend Point Cross_Point(Line& l1,Line& l2){
        return Cross_Point(l1.p1,l1.p2,l2.p1,l2.p2);
    }

    friend double dis(Line l,Point p){return fabs(Dot(l.Dir.Normal(),p)/Getlen(l.Dir.Normal()));}
};



struct node{
    int number;Point P[300];Line L[300];
    Point Heavy_Point;

    node(){;}
    void Build();
    double getArea();
    node Cut(Line&cutter);
} tot,sec1,sec2,ret;

void node::Build()
{
    sort(P+1,P+1+number);
    for(int i=1;i<number;i++){
        L[i+number]=L[i]=Line(P[i],P[i+1]);
    }
    L[number<<1]=L[number]=Line(P[number],P[1]);
}

node node::Cut(Line&cutter)
{
    int st=-1,ed=-1;

    for(int i=1;i<=number;i++){
        if( isCross(cutter,L[i]) ){
            if(st==-1){
                st=i;
            }else{
                ed=i;
				break;
            }
        }
    }
    if(~st && ~ed){
    //决定遍历顺序
        double delt=P[st].angle-P[ed].angle;
        if(delt<0)
          delt=P[ed].angle-P[st].angle;
        int& cnnt=ret.number;
        cnnt=0;
        ret.Heavy_Point.x=ret.Heavy_Point.y=0;
        if(delt>PI){
        	ret.Heavy_Point+=(ret.P[++cnnt]=Cross_Point(cutter,L[st]));
            for(int i=ed+1;i<=number+st;i++){
            	ret.Heavy_Point+=(ret.P[++cnnt]=P[i]);
            }
        	ret.Heavy_Point+=(ret.P[++cnnt]=Cross_Point(cutter,L[ed]));
        }else{
        	ret.Heavy_Point+=(ret.P[++cnnt]=Cross_Point(cutter,L[st]));
            for(int i=st+1;i<=ed;i++){
            	ret.Heavy_Point+=(ret.P[++cnnt]=P[i]);
            }
       	 	ret.Heavy_Point+=(ret.P[++cnnt]=Cross_Point(cutter,L[ed]));
        }

        ret.Heavy_Point+=(ret.P[++cnnt]=Cross_Point(cutter,L[st]));
        ret.Heavy_Point+=(ret.P[++cnnt]=Cross_Point(cutter,L[ed]));

        ret.Heavy_Point/=cnnt;
        ret.Build();
    }
	return ret;
}

double node::getArea()
{
    double ret=0;
    for(int i=1;i<number;i++){
        ret+=fabs( Cross(P[i]-Heavy_Point,P[i+1]-Heavy_Point) );
    }
    ret+=fabs( Cross(P[number]-Heavy_Point,P[1]-Heavy_Point) );
    return ret/2;
}

int main()
{
//    Point var1(1,-sqrt(3));
//    Point var1(1,-1);
//    cout<<Getangle( var1,Point(1,0) );
//    cout<<Getlen(var1);
//    Line l1(1,1,0),l2(1,-1,2);
//    Point var=Cross_Point(l1,l2);
//    cout<<var.x<<' '<<var.y<<'\n';
//	node var;
//	cout<<var.getArea();

    int n;cin>>n;
    tot.number=n;
    for(int i=1;i<=n;i++){
    	double x,y;
    	cin>>x>>y;
        tot.P[i]=Point(x,y);
        tot.Heavy_Point+=tot.P[i];
    }
    tot.Heavy_Point/=n;
    tot.Build();

    double w,px,py,fx,fy;
    
    cin>>w>>px>>py>>fx>>fy;
    Line cutter(Point(px,py),Point(fx,fy));

    Line cutter1(cutter.Parallel_move(w/2));
    cutter1.p1-=cutter1.Dir*1000;
    cutter1.p2+=cutter1.Dir*1000;

    Line cutter2(cutter.Parallel_move(-w/2));
    cutter2.p1-=1000*cutter2.Dir;
    cutter2.p2+=1000*cutter2.Dir;

	if( dis(cutter1,tot.Heavy_Point)<=w/2 || dis(cutter2,tot.Heavy_Point)<=w/2 ){
	    sec1=tot.Cut(cutter1);
	    sec2=tot.Cut(cutter2);
	    cout<<fixed;
	    cout<<setprecision(6)<<100-floor(( ( sec1.getArea()+sec2.getArea() )*100000000 )/(tot.getArea()) )/1000000<<endl;
	}else{
		cout<<"100.000000"<<endl;
	}

    return 0;
}

没有规划的学习就是纯摆,浪费时间。

入门题单:
OIer分享
LUOGU
VJ——WORKBOOK

计算几何题的特点与做题要领:

1.大部分不会很难,少部分题目思路很巧妙
2.做计算几何题目,模板很重要,模板必须高度可靠。
3.要注意代码的组织,因为计算几何的题目很容易上两百行代码,里面大部分是模 板。如果代码一片混乱,那么会严重影响做题正确率。
4.注意精度控制。能用整数的地方尽量用整数,要想到扩大数据的方法(扩大一倍, 或扩大sqrt2)。因为整数不用考虑浮点误差,而且运算比浮点快。

会更新的板子:

#include<bits/stdc++.h>

using namespace std;

const double EPS=1e-8;
const double PI=acos(-1);

int sgn(double number,double eps=1e-8){if(fabs(number)<eps)return 0;else return number>0?1:-1;}

struct Point{
	double x;
	double y;
	double angle;
	Point() {;}
	Point(double vx,double vy):x(vx),y(vy){double theta=acos(x/sqrt(x*x+y*y)) , temp=asin(y/sqrt(x*x+y*y));angle=temp>0?theta:2*PI-theta;	}

	friend Point operator+(Point p1,Point p2){return Point(p1.x+p2.x,p1.y+p2.y);}
	friend Point operator-(Point p1,Point p2){return Point(p1.x-p2.x,p1.y-p2.y);}
	friend Point operator*(Point var,double factor){return Point(var.x*factor,var.y*factor);}
	friend Point operator*(double factor,Point var){return Point(var.x*factor,var.y*factor);}
	friend Point operator/(Point var,double factor){return Point(var.x/factor,var.y/factor);}
    void operator+=(Point &var){x+=var.x,y+=var.y;}
    void operator-=(Point &var){x-=var.x,y-=var.y;}
    void operator*=(Point &var){x*=var.x,y*=var.y;}
    void operator/=(Point &var){x/=var.x,y/=var.y;}
};


struct Line {
    //点向式
	Point p1,p2,Dir;
	double A,B,C;
    bool isSegment;

	Line() {;}
	Line(Point vp1,Point vp2,bool Seg=0):p1(vp1),p2(vp2),isSegment(Seg){if(p1.x>p2.x)swap(p1,p2);Dir=p2-p1;A=p2.y-p1.y,B=p1.x-p2.x,C=-(p1.x*p2.y-p2.x*p1.y);}
	Line(double a,double b,double c,bool Seg=0):A(a),B(b),C(c),isSegment(Seg){if( !sgn(a) ){ p1=Point(0,-c/b),p2=Point(1,-c/b);}else if( !sgn(b) ) {p1=Point(-c/a,0),p2=Point(-c/a,1);}else {p1=Point(0,-c/b),p2=Point(1,(-a-c)/b);}}


};
#define Segment Line

struct Circle {
    Point center;
	double r;
	Circle(){;}
	Circle(double vx,double vy,double vr):center(vx,vy),r(vr) {;}
	Circle(Point var,double vr):center(var),r(vr) {;}
};


namespace Calgeo {

    double Getdot(Point p1,Point p2){return (p1.x*p2.x+p1.y*p2.y);}
    double Getcross(Point p1,Point p2){return (p1.x*p2.y-p1.y*p2.x);}

    double Getlen(Point var){return sqrt(var.x*var.x+var.y*var.y);}
    double Getlen2(Point var){return var.x*var.x+var.y*var.y;}
    double Getlen(Point p1,Point p2){return Getlen(p1-p2);}
    double Getlen2(Point p1,Point p2){return Getlen2(p1-p2);}

    //单位法向量
    Point Normal(Point var){return Point(-var.y,var.x)/Getlen(var);}
    double Getangle(Point p1,Point p2){return acos(Getdot(p1,p2));}

    double Getdis(Point p1,Point p2) {return Getlen(p1-p2);}
    double Getdis(Line l,Point p) {return fabs(Getcross(l.p1-p,Normal(l.Dir))) ;}
    double Getdis(Circle c,Point p) {return Getdis(p,c.center);}
    double Getdis(Line l,Circle c) {return Getdis(l,c.center);}
    double Getproj(Line l,Point p) {return fabs(Getdot(p,l.Dir)) ;}


    bool Isparallel(Point p1,Point p2){return p1.angle==p2.angle;}
    bool Isparallel(Line l1,Line l2){return Isparallel(l1.Dir,l2.Dir);}
    bool Iscross(Point a,Point b,Point c,Point d){double c1=Getcross(b-a,d-a),c2=Getcross(b-a,c-a),d1=Getcross(d-c,b-c),d2=Getcross(d-c,a-c);return sgn(c1)*sgn(c2)<0 && sgn(d1)*sgn(d2)<0 ;}
    bool IscrossEdge(Point a,Point b,Point c,Point d){double c1=Getcross(b-a,d-a),c2=Getcross(b-a,c-a),d1=Getcross(d-c,b-c),d2=Getcross(d-c,a-c);return sgn(c1)*sgn(c2)<=0 && sgn(d1)*sgn(d2)<=0 ;}


    int Cnt_Crosspoint(Line l,Circle c){double temp=Getdis(l,c);if(temp>c.r)return 0;else if(temp==c.r)return 1;else return 2;}
//    int Cnt_Crosspoint(Line l1,Line l2){if(Isparallel(l1,l2)){return 0;}else if(l1.isSegment){}else if(l2.isSegment){}else{}  ;}

    Point Getcrosspoint(Point a,Point b,Point c,Point d){double s1=Getcross(b-a,c-a),s2=Getcross(b-a,d-a);return Point(c.x*s2-d.x*s1,c.y*s2-d.y*s1)/(s2-s1);}
    Point Getcrosspoint(Line l1,Line l2){return Getcrosspoint(l1.p1,l1.p2,l2.p1,l2.p2);}
//    Point Getcrosspoint(Line l,Circle c){;}
}

using namespace Calgeo;

signed main(void)
{

	return 0;
}

总结起来就是,一股脑地写了很多东西,以为自己懂很多。事实上这些计算几何的内容里面很多都是高中数学的向量、平面几何、立体几何、解析几何的内容,大学高数又教了很多东西。所以学起来不痛苦。
但是要注意时间啊!浪费了很多时间但是却没有什么收获,学这个是为了AC率和思维,其他的什么快感放一边去。

posted @ 2023-05-01 20:44  ZZQ323  阅读(20)  评论(0)    收藏  举报