zoukankan      html  css  js  c++  java
  • BZOJ2618 [Cqoi2006]凸多边形 凸包 计算几何

    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ2618


    题意概括

      给出多个凸包,求面积交。


    题解

      首先我们考虑两个凸包相交的情况。

      例题:HDU1632

      我们可以证明,两个凸包相交,如果面积交为正,那么新构成的面积块一定也是一个凸包。

      具体证明可以分情况讨论,反正画几个图就明白了。也可以网上查一查。

      那么题目就简单了。

      变成了一道水水的码农题。

      两个凸包面积交之后,还是凸包,所以,题目就变成了依次进行面积交。

      只需要考虑两个凸包相交的情况。

      构成的新凸包上的顶点只有可能是两类:

      1.  原来两个凸包的某一个的顶点,并且处于另一个凸包内。

      2.  原来两个凸包的交点。

      那么只需要最暴力的揪出这些点就可以了。

      判断一个点是否在里面,可以用面积法。

      当然网上有很多其他的方法。

      求线段交点,方法就很多了。一搜一大堆的。


    代码

    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    const double Eps=1e-8;
    int Dcmp(double a){
    	if (fabs(a)<Eps)
    		return 0;
    	return a<0?-1:1;
    }
    int Dcmp(double x,double y){
    	return Dcmp(x-y);
    }
    struct Point{
    	double x,y;
    	Point (){}
    	Point (double x_,double y_){
    		x=x_,y=y_;
    	}
    	Point operator + (Point a){
    		return Point(x+a.x,y+a.y);
    	}
    	Point operator - (Point a){
    		return Point(x-a.x,y-a.y);
    	}
    	Point operator * (double a){
    		return Point(x*a,y*a);
    	}
    	Point operator / (double a){
    		return Point(x/a,y/a);
    	}
    };
    double cross(Point a,Point b){
    	return a.x*b.y-a.y*b.x;
    }
    double cross(Point a,Point b,Point c){
    	return cross(b-a,c-a);
    }
    double Dot(Point a,Point b){
    	return a.x*b.x+a.y*b.y;
    }
    double dis(Point a,Point b){
    	return sqrt(Dot(a-b,a-b));
    }
    Point readPoint(){
    	double x,y;
    	scanf("%lf%lf",&x,&y);
    	return Point(x,y);
    }
    struct Line{
    	Point a,b;
    	Line (){}
    	Line (Point x,Point y){
    		a=x,b=y;
    	}
    };
    bool Lcross(Line L1,Line L2){
    	return Dcmp(cross(L1.a,L2.a,L2.b))*Dcmp(cross(L1.b,L2.a,L2.b))<0;
    }
    bool crossed(Line L1,Line L2){
    	return Lcross(L1,L2)&&Lcross(L2,L1);
    }
    Point Cross_Point(Line a,Line b){
        Point P=a.a,Q=b.a,v=a.b-a.a,w=b.b-b.a,u=P-Q;
    	double t=cross(w,u)/cross(v,w);
    	return P+v*t;
    }
    Point O;
    bool cmpAngle(Point a,Point b){
    	double cr=cross(O,a,b);
    	if (Dcmp(cr)==0)
    		return dis(O,a)<dis(O,b);
    	return cr>0;
    }
    struct Ploygon{
    	static const int M=600;
    	int m;
    	Point P[M];
    	double Area;
    	void clear(){
    		m=0;
    		Area=-1;
    	}
    	void add(Point x){
    		for (int i=1;i<=m;i++)
    			if (Dcmp(x.x,P[i].x)==0&&Dcmp(x.y,P[i].y)==0)
    				return;
    		P[++m]=x;
    	}
    	bool cmpO(Point a,Point b){
    		if (Dcmp(a.y,b.y)==0)
    			return Dcmp(a.x,b.x)<=0;
    		return Dcmp(a.y,b.y)<0;
    	}
    	void buildPloygon(){
    		int st[M],top=0;
    		O=P[1];
    		for (int i=2;i<=m;i++)
    			if (!cmpO(O,P[i]))
    				O=P[i];
    		sort(P+1,P+m+1,cmpAngle);
    		st[++top]=1,st[++top]=2;
    		for (int i=3;i<=m;i++){
    			while (top>=2&&Dcmp(cross(P[st[top-1]],P[st[top]],P[i]))<0)
    				top--;
    			st[++top]=i;
    		}
    		for (int i=1;i<=top;i++)
    			P[i]=P[st[i]];
    		m=top;
    	}
    	double area(){
    		if (Dcmp(Area,-1)!=0)
    			return Area;
    		Area=0;
    		for (int i=2;i<m;i++)
    			Area+=fabs(cross(P[1],P[i],P[i+1]));
    		Area/=2;
    		return Area;
    	}
    	bool inside(Point x){
    		double ar=0;
    		for (int i=1;i<=m;i++)
    			ar+=fabs(cross(x,P[i],P[i%m+1]));
    		ar/=2;
    		return Dcmp(area(),ar)==0;
    	}
    }P1,P2,P3;
    int n,m;
    int main(){
    	scanf("%d",&n);
    	for (int cnt=1;cnt<=n;cnt++){
    		P2.clear();
    		scanf("%d",&m);
    		while (m--)
    			P2.add(readPoint());
    		P2.buildPloygon();
    		if (cnt==1){
    			P1=P2;
    			continue;
    		}
    		P3.clear();
    		for (int i=1;i<=P1.m;i++)
    			if (P2.inside(P1.P[i]))
    				P3.add(P1.P[i]);
    		for (int i=1;i<=P2.m;i++)
    			if (P1.inside(P2.P[i]))
    				P3.add(P2.P[i]);
    		for (int i=1;i<=P1.m;i++)
    			for (int j=1;j<=P2.m;j++){
    				Line L1=Line(P1.P[i],P1.P[i%P1.m+1]),L2=Line(P2.P[j],P2.P[j%P2.m+1]);
    				if (crossed(L1,L2))
    					P3.add(Cross_Point(L1,L2));
    			}
    		P3.buildPloygon();
    		if (Dcmp(P3.area())==0){
    			printf("0.000");
    			return 0;
    		}
    		P1=P3;
    	}
    	printf("%.3lf",P1.area());
    	return 0;
    }
    

      

  • 相关阅读:
    koa2学习(二) 中间件router
    行内元素与块级函数的三个区别
    Mobile Matrices
    jquery中attr()与prop()函数用法实例详解(附用法区别)
    jquery 鼠标右键事件、左键单击事件判定
    JS回调函数(callback)
    js关闭当前页面 (窗口)的几种方式总结
    em(倍)与px的区别
    jQuery学习笔记
    通过JS判断联网类型和连接状态
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ2618.html
Copyright © 2011-2022 走看看