zoukankan      html  css  js  c++  java
  • [CQOI2006]凸多边形

    题目

    wdnmd可算调出来了,以后我也是会半平面交的人了

    由于给定的是一些凸包,我们直接按照逆时针把所有直线搞下来,我们默认保留直线左边的半平面;之后我们就可以按照极角序把直线排序,对于两条极角相等的直线,显然是更靠近左边的优,于是我们只保留最靠左的直线

    与凸包不同的是,我们使用一个双端队列维护半平面交,对于一条要插入的直线(l),我们发现队尾两条直线的交点(p)(l)的右侧,那么就说明队尾的直线没啥用了,就弹出去;同理,如果队首两条直线的交点在(l)右侧,也将队首直线弹出

    可以康康这个老哥博客里的图

    最后还有可能出现队尾两条直线的交点在队首直线的右侧的情况,对于这种情况我们弹掉队尾就好了

    代码

    #include<bits/stdc++.h>
    #define re register
    const int maxn=505;
    struct Point{double x,y;}p[maxn],a[maxn],S;
    const double eps=1e-8;
    int n,cnt,tot,h,t,tmp;
    struct Line{Point s,t;double det;}L[maxn],q[maxn];
    inline Point operator+(Point A,Point B) {return (Point){A.x+B.x,A.y+B.y};}
    inline Point operator-(Point A,Point B) {return (Point){A.x-B.x,A.y-B.y};}
    inline Point operator^(double g,Point C) {return (Point){C.x*g,C.y*g};}
    inline double operator*(Point A,Point B) {return A.x*B.y-B.x*A.y;}
    inline int dcmp(double A,double B) {return A+eps>B&&A-eps<B;}
    inline int OnRight(const Point &a,const Line &c) {
    	return (c.t-a)*(c.s-a)>0;
    }
    inline int cmp(const Line &A,const Line &B) {
    	return dcmp(A.det,B.det)?OnRight(A.s,B):(A.det<B.det);
    }
    inline Point sec(const Line &A,const Line &B) {
    	Point v1=A.t-A.s,v2=B.t-B.s,v3=A.s-B.s;
    	double t=(v3*v2)/(v2*v1);
    	return A.s+(t^v1);
    }
    int main() {
    	scanf("%d",&n);S.x=1e18,S.y=1e18;
    	for(re int m,i=1;i<=n;i++) {
    		scanf("%d",&m);
    		for(re int j=1;j<=m;j++) scanf("%lf%lf",&a[j].x,&a[j].y);
    		for(re int j=1;j<m;++j) L[++cnt].s=a[j],L[cnt].t=a[j+1];
    		L[++cnt].s=a[m],L[cnt].t=a[1];
    	}
    	for(re int i=1;i<=cnt;i++) 
    		L[i].det=atan2((L[i].t-L[i].s).y,(L[i].t-L[i].s).x);
    	std::sort(L+1,L+cnt+1,cmp);h=1,t=0;tot=0;
    	for(re int i=1;i<=cnt;i++) {
    		if(!dcmp(L[i].det,L[i-1].det)) ++tot;
    		L[tot]=L[i];
    	}
    	q[++t]=L[1],q[++t]=L[2];
    	for(re int i=3;i<=tot;i++) {
    		while(h<t&&OnRight(sec(q[t],q[t-1]),L[i])) --t;
    		while(h<t&&OnRight(sec(q[h],q[h+1]),L[i])) ++h;
    		q[++t]=L[i];
    	}
    	while(h<t&&OnRight(sec(q[t],q[t-1]),q[h])) --t;
    	while(h<t&&OnRight(sec(q[h],q[h+1]),q[t])) ++h;
    	for(re int i=h;i<t;i++) p[++tmp]=sec(q[i],q[i+1]);p[++tmp]=sec(q[t],q[h]);
    	double ans=p[tmp]*p[1];
    	for(re int i=1;i<tmp;i++) ans+=p[i]*p[i+1];
    	printf("%.3lf
    ",ans*0.5);return 0;
    }
    
  • 相关阅读:
    CentOS7.6配置ip
    查看当前用户下没有主键也没有唯一性索引的表
    C++ 开机自动启动
    C++ 判断是文件还是文件夹
    Duilib热键
    c++将字符转换成字符串
    duilib中各控件响应的消息类型
    Duilib程序添加托盘图标显示
    C++打开文件夹
    C++获取驱动盘句柄
  • 原文地址:https://www.cnblogs.com/asuldb/p/12159471.html
Copyright © 2011-2022 走看看