zoukankan      html  css  js  c++  java
  • CF几何刷题记录

    不开坑就没有方向……
    (虽然开了坑也会跑路……)
    UPD:退役了退役了,跑路跑路
    想把CF里过题人数100+的几何题都做一做……
    那就先从1000-往下做吧

    模板:

    #include<bits/stdc++.h>
    #define ERROR 1e99
    #define N 100005
    using namespace std;
    typedef double data;
    typedef long long LL;
    const data PI=acos(-1.);
    const data EPS=1E-10;
    int Zero(data O){return fabs(O)<=EPS;}
    void Read(data &now){double IO;scanf("%lf",&IO);now=IO;}
    struct Point{
    	data x,y;
    	void read(){Read(x);Read(y);}
    	void Print(){printf("%lf %lf
    ",(double)x,(double)y);}
    	void init(data _x,data _y){x=_x;y=_y;}
    	data operator * (const Point &b)const{
    		return x*b.y-y*b.x;
    	}
    	Point operator * (const data &b)const{
    		return (Point){x*b,y*b};
    	}
    	data operator ^ (const Point &b)const{
    		return x*b.x+y*b.y;
    	}
    	Point operator - (const Point &b)const{
    		return (Point){x-b.x,y-b.y};
    	}
    	Point operator + (const Point &b)const{
    		return (Point){x+b.x,y+b.y};
    	}
    	int operator < (const Point &b)const{
    		return x<b.x||x==b.x&&y<b.y;
    	}
    	int operator == (const Point &b)const{
    		return Zero(x-b.x)&&Zero(y-b.y);
    	}
    	void Rotate(data alpha){
    		data _x=x*cos(alpha)-y*sin(alpha);
    		data _y=y*cos(alpha)+x*sin(alpha);
    		x=_x;y=_y;
    	}
    }ERRORPOINT=(Point){ERROR,ERROR};
    struct Line{
    	Point p,q;
    };
    struct Circle{
    	Point O;data r;
    	void read(){O.read();Read(r);}
    };
    data sqr(data x){return x*x;}
    data dist(Point A,Point B){return sqrt(sqr(A.x-B.x)+sqr(A.y-B.y));}
    int Intersection(Line A,Line B,Point &ret){
    	ret=A.p;
    	data u=(A.p-B.p)*(B.p-B.q);
    	data v=(A.p.x-A.q.x)*(B.p.y-B.q.y)-(A.p.y-A.q.y)*(B.p.x-B.q.x);
    	if (Zero(v)) return 0;u/=v;
    	ret.x+=(A.q.x-A.p.x)*u;
    	ret.y+=(A.q.y-A.p.y)*u;
    	return 1;
    }
    int Intersection(Circle C,Line L,Point &A,Point &B){
    	Point p=C.O;p.x+=L.p.y-L.q.y;p.y+=L.q.x-L.p.x;
    	Intersection((Line){p,C.O},L,p);
    	data tmp=sqr(C.r)-sqr(p.x-C.O.x)-sqr(p.y-C.O.y);
    	if (tmp<-EPS) return 0;
    	data t=sqrt(max(tmp,0.))/dist(L.p,L.q);
    	A=p+(L.q-L.p)*t;B=p-(L.q-L.p)*t;
    	return 1;
    }
    int Intersection(Circle C1,Circle C2,Point &A, Point &B) {
    	double d = dist(C1.O,C2.O);
    	if (d<fabs(C1.r-C2.r)-EPS || d>fabs(C1.r+C2.r)+EPS) return 0;
    	double cosa = (sqr(C1.r) + sqr(d) - sqr(C2.r)) / (2 * C1.r * d);
    	double sina = sqrt(max(0., 1. - sqr(cosa)));
    	A = B = C1.O;
    	A.x += C1.r / d * ((C2.O.x - C1.O.x) * cosa + (C2.O.y - C1.O.y) * -sina);
    	A.y += C1.r / d * ((C2.O.x - C1.O.x) * sina + (C2.O.y - C1.O.y) * cosa);
    	B.x += C1.r / d * ((C2.O.x - C1.O.x) * cosa + (C2.O.y - C1.O.y) * sina);
    	B.y += C1.r / d * ((C2.O.x - C1.O.x) *-sina + (C2.O.y - C1.O.y) * cosa);
    	return 1;
    }
    
    //此处默认data是int 
    int Polar_cmp(const Point &A,const Point &B){
    	if (A.y==0&&B.y==0) return A.x>0&&B.x<0;
    	if (A.y==0) return A.x>0||B.y<0;
    	if (B.y==0) return B.x<0&&A.y>0;
    	if ((A.y>0)^(B.y>0)) return A.y>0;
    	return (A*B)>0;
    }
    
    vector<Point>Make_Convex(vector<Point>now){
    	sort(now.begin(),now.end());
    	if (now.size()<3) return now;
    	for (int i=0;i<now.size();i++)
    		now[i].Print();
    	puts("");
    	
    	vector<Point>up;up.clear();
    	up.push_back(now[0]);
    	for (int i=1;i<now.size();i++){
    		for (;up.size()>1&&(up[up.size()-2]-up.back())*(now[i]-up.back())<=0;up.pop_back());
    		up.push_back(now[i]);
    	}
    	vector<Point>down;down.clear();
    	down.push_back(now.back());
    	for (int i=now.size()-1;i>=0;i--){
    		for (;down.size()>1&&(down[down.size()-2]-down.back())*(now[i]-down.back())<=0;down.pop_back());
    		down.push_back(now[i]);
    	}
    	
    	vector<Point>ret;ret.clear();
    	for (int i=down.size()-1;i>0;i--)
    		ret.push_back(down[i]);
    	for (int i=up.size()-1;i>0;i--)
    		ret.push_back(up[i]);
    	return ret;
    }
    
    //以下是最小圆覆盖
    
    //两个点 
    Circle make_2(Point p,Point q){
    	Circle ret;
    	ret.O.x=(p.x+q.x)/2.0;
    	ret.O.y=(p.y+q.y)/2.0;
    	ret.r=dist(ret.O,p);
    	return ret;
    }
    //返回三角形的外心  
    Circle make_3(const Point &a,const Point &b,const Point &c)  {
        data a1=b.x-a.x,b1=b.y-a.y,c1=(a1*a1+b1*b1)/2;  
        data a2=c.x-a.x,b2=c.y-a.y,c2=(a2*a2+b2*b2)/2;  
        data d=a1*b2-a2*b1;
        Circle ret;
        ret.O.x=a.x+(c1*b2-c2*b1)/d;
        ret.O.y=a.y+(a1*c2-a2*c1)/d;
        ret.r=dist(ret.O,a);
        return ret;
    } 
    bool IN(Circle now,Point a){
    	return (dist(now.O,a)<=now.r+EPS);
    }
    Circle Smallest_Circle(Point *a,int n){
    	if (n==1) return (Circle){a[1],0};
    	srand(2333);
    	random_shuffle(a+1,a+n+1);
    	Circle cur=make_2(a[1],a[2]);
    	for (int i=2;i<=n;i++)
    		if (!IN(cur,a[i])){
    			cur=make_2(a[1],a[i]);
    			for (int j=1;j<i;j++)
    				if (!IN(cur,a[j])){
    					cur=make_2(a[i],a[j]);
    					for (int k=1;k<j;k++)
    						if (!IN(cur,a[k]))
    							cur=make_3(a[i],a[j],a[k]);
    				}
    		}
    	return cur;
    }
    int main(){
    }
    

    【280A】
       有一个水平放置的长方形。求它绕中心旋转(alpha)度后的图形与原图形的面积交。
       直接分类讨论感觉很烦烦。本来想趁机搞一个HPI的板子,可是放弃了……
       后来用了一个比较巧妙的做法。把两个矩形的边框拿来交一交,只有都在两条直线内的交点才会是最终答案凸包上的点。然后随便做个凸包就好了。

    【793C】
       有一坨给定初始坐标和方向向量的点,还有一个固定的矩形。问一个最早的时刻,使得所有点都严格在矩形内部。
       因为是矩形,把直线画出来后,最多只会与矩形交两个unique的点(注意到<2必然是无解)。然后算一算对应时间求个交即可。
       此题最大的坑点是“严格”。最后的合法区间如果只有一个值,那么其实是不合法的;这个eps就很耐人寻味。还要注意那些和边框重合的运动路线也是不合法的。

    【166B】
       分析一下题目性质,转化为问一个点是否严格在一个凸包内部。
       分别维护出上凸壳和下凸壳,每次二分后用叉积判断即可。

    【600D】
       求两个圆面积交……看起来很old,确是一道特别帅气的题……
       其实就是求两个弓形的面积。我本来是直接求交点,用叉积计算三角形面积,然后余弦定理算一下扇形的角度。
       但是数据范围太大了,求交的精度会爆炸……
       其实知道了半径和距离后,换个三角形研究,即可算出扇形的角度……然后根据角度再计算三角形。
       仔细想想,这也能开发出求交的另一个方法。虽然有三角函数,但感觉精度靠谱很多。

    【2C】
       对于其中两个圆,可以发现符合要求的点在一条直线或者一个圆上。
       那么最终答案就在圆/直线与圆/直线的交点上。检验板子的好题……

  • 相关阅读:
    Git
    Git
    Git
    Git
    Docker
    Linux
    Linux
    Python
    Python
    SQL
  • 原文地址:https://www.cnblogs.com/jiangshibiao/p/8456297.html
Copyright © 2011-2022 走看看