ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

计算几何-半平面交

2022-05-29 19:01:50  阅读:202  来源: 互联网

标签:b2 double a1 b1 计算 几何 平面 geometric


计算几何-半平面交

半平面

平面内的一条直线把这个平面分成两部分,每一部分对这个平面来说,都叫做半平面。包括这条直线的半平面叫做闭半平面,否则叫做开半平面。

解析式为 \(Ax + By +C >=0\)或\(Ax + By +C <=0\)。

在计算几何中用向量表示,整个题统一以向量的左侧或右侧为半平面。

半平面交

半平面交就是多个半平面的交集。半平面交是一个点集。

它可以理解为向量集中每一个向量的右侧的交,或者是下面方程组的解。

\[ \begin{equation} \begin{cases} A1x+B1y+C1\ge0\newline A2x+B2y+C2\ge0\newline ~~~~~~~~~~~~~~\dots \end{cases} \end{equation} \]

多边形的核

如果一个点集中的点与多边形上任意一点的连线与多边形没有其他交点,那么这个点集被称为多边形的核。

把多边形的每条边看成是首尾相连的向量,那么这些向量在多边形内部方向的半平面交就是多边形的核。

求法

D&C算法

该算法是基于分治思想的:

  • 将\(n\)个半平面分成两个\(n/2\)的集合;

  • 对两个子集和递归求解半平面交;

  • 将前一步算出来的两个交利用平面扫描法求解。

时间复杂度\((n \log n)\)这个算法并不常用,主要介绍的是下面这个。

S&I算法

该算法是在2006年有中国队队员朱泽园提出来的“排序增量法”。

假设给出\(n\)条直线,求这\(n\)条直线的左方半平面的交集:

  • 首先对这\(n\)条直线按极角排序;

  • 用一个队列去维护半平面的交集,和相邻两条直线的交点;

  • 每次加入新的直线时判断是否有交点在该直线的右面,如果是则弹出直线,先判队尾再判队首,注意判断平行情况;

  • 最后队列中的交集即为半平面交。

【模板】半平面交

Code:

#include<bits/stdc++.h>
#define eps 1e-8
using namespace std;
const int maxn=1010;
struct geometric{
    double x,y;
    geometric(double X=0,double Y=0):x(X),y(Y) {}
    friend geometric operator + (const geometric a,const geometric b){return geometric(a.x+b.x,a.y+b.y);} 
    friend geometric operator - (const geometric a,const geometric b){return geometric(a.x-b.x,a.y-b.y);} 
    friend geometric operator * (const geometric a,double p){return geometric(a.x*p,a.y*p);}
    friend geometric operator / (const geometric a,double p){return geometric(a.x/p,a.y/p);}
    double dis(geometric a,geometric b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
    double dot(geometric a1,geometric a2,geometric b1,geometric b2){return (a2.x-a1.x)*(b2.x-b1.x)+(a2.y-a1.y)*(b2.y-b1.y);}
    double cross(geometric a1,geometric a2,geometric b1,geometric b2){return (a2.x-a1.x)*(b2.y-b1.y)-(a2.y-a1.y)*(b2.x-b1.x);}
    double corner(geometric a1,geometric a2,geometric b1,geometric b2){return dot(a1,a1,b1,b2)/(dis(a1,a2)*dis(b1,b2));}
    double area(geometric a1,geometric a2,geometric b1,geometric b2){return fabs(cross(a1,a2,b1,b2));}
    double angle(geometric a){return atan2(a.y,a.x);}
}opt;
int n,m,tot,head=1,tail=1;double ans;
geometric data[maxn],origin,T[maxn];
struct line{
    geometric A,B;double An;
    line(geometric a,geometric b):A(a),B(b) {An=opt.angle(B);}
    line(){}
    bool operator < (const line &a)const{return An<a.An;}
    geometric sdot(line a,line b){
        geometric c=a.A-b.A;
        double k=opt.cross(origin,b.B,origin,c)/opt.cross(origin,a.B,origin,b.B);
        return a.A+a.B*k;
    }
}q[maxn],p[maxn],take;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&m);
        for(int j=1;j<=m;j++)
        scanf("%lf%lf",&data[j].x,&data[j].y);
        for(int j=1;j<=m;j++)
        {
            if(j==m)p[++tot]=line(data[j],data[1]-data[j]);
            else p[++tot]=line(data[j],data[j+1]-data[j]);
        }
    }
    sort(p+1,p+tot+1);
    q[head]=p[head];
    for(int i=2;i<=tot;i++)
    {
        while(head<tail&&opt.cross(origin,p[i].B,p[i].A,T[tail-1])<=eps)tail--;
        while(head<tail&&opt.cross(origin,p[i].B,p[i].A,T[head])<=eps)head++;
        q[++tail]=p[i];
        if(fabs(opt.cross(origin,q[tail].B,origin,q[tail-1].B))<=eps)
        {
            tail--;
            if(opt.cross(origin,q[tail].B,q[tail].A,p[i].A)>eps)q[tail]=p[i];
        }
        if(head<tail)T[tail-1]=take.sdot(q[tail-1],q[tail]);
    }   
    while(head<tail&&opt.cross(origin,q[head].B,q[head].A,T[tail-1])<=eps)tail--;
    if(tail-head>1)
    T[tail]=take.sdot(q[head],q[tail]);
    for(int i=head;i<=tail;i++)
    {
        if(i==tail)ans+=opt.cross(origin,T[i],origin,T[head]);
        else ans+=opt.cross(origin,T[i],origin,T[i+1]);
    }
    printf("%.3lf",ans/2);
    return 0;
}

一些例题

[ZJOI2008]瞭望塔

[HNOI2008]水平可见直线

[JLOI2013]赛车

[HNOI2012]射箭

标签:b2,double,a1,b1,计算,几何,平面,geometric
来源: https://www.cnblogs.com/Jekyll-Y/p/16324580.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有