【模板/经典题型】半平面交

写半平面交的时候注意以下几点
1.考虑x,y是否有正负号限制。
2.注意特判分母为0的情况。
3.对于分母正负不确定的情况分类讨论。

#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#define N 1100000
#define L 1000000
#define eps 1e-7
#define inf 1e9+7
#define db double
#define ll long long
#define ldb long double
using namespace std;
inline int read()
{
    char ch=0;
    int x=0,flag=1;
    while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*flag;
}
const db phi=acos(-1);
int dcmp(db x)
{
    if(fabs(x)<=eps)return 0;
    else return x>0?+1:-1;
}
struct vec
{
    db x,y;
    vec(db xx=0,db yy=0){x=xx,y=yy;}
    db ang(){return atan2(y,x);}
    db len(){return sqrt(x*x+y*y);}
    vec operator+(vec a){return (vec){x+a.x,y+a.y};}
    vec operator-(vec a){return (vec){x-a.x,y-a.y};}
    vec operator*(db k){return (vec){x*k,y*k};}
    vec operator/(db k){return (vec){x/k,y/k};}
    bool operator==(vec a){return !dcmp(x-a.x)&&!dcmp(y-a.y);}
}p[N];
typedef vec pot;
db dot(vec a,vec b){return a.x*b.x+a.y*b.y;}
db cross(vec a,vec b){return a.x*b.y-a.y*b.x;}
struct line
{
    pot s,t;db ang;
    line(pot ss=vec(),pot tt=vec()){s=ss;t=tt;ang=(tt-ss).ang();}
}f[N];
bool cmp(line a,line b)
{
    int k=dcmp(a.ang-b.ang);
    if(k)return k<0;
    else return dcmp(cross(a.t-a.s,b.t-a.s))<0; 
}
bool pal(line a,line b)
{
    return !dcmp(cross(a.t-a.s,b.t-b.s));
}
pot get(line a,line b)
{
    return a.s+(a.t-a.s)*(cross(b.t-b.s,a.s-b.s)/cross(a.t-a.s,b.t-b.s));
}
bool onright(pot a,line l)
{
    return dcmp(cross(a-l.s,l.t-l.s))>0;
}
pot Q[N];
line q[N];
db solve(int cnt)
{
    int l=1,r=1;q[1]=f[1];
    for(int i=2;i<=cnt;i++)
    if(dcmp(f[i].ang-f[i-1].ang))
    {
        if(l<r&&(pal(q[l],q[l+1])||pal(q[r],q[r-1])))return 0;
        while(l<r&&onright(Q[r-1],f[i]))r--;
        while(l<r&&onright(Q[l],f[i]))l++;
        q[++r]=f[i];Q[r-1]=get(q[r-1],q[r]);
    }   
    while(l<r&&onright(Q[r-1],q[l]))r--;
    while(l<r&&onright(Q[l],q[r]))l++;
    if(r-l<=1)return 0;
    Q[r]=get(q[l],q[r]);
    db ans=0;
    for(int i=l;i<=r;i++)
    {
        if(i!=r)ans+=cross(Q[i],Q[i+1]);
        else ans+=cross(Q[r],Q[l]);
    }
    return fabs(ans)/2.0;
}
int main()
{
    int n=read(),cnt=0;
    for(int o=1;o<=n;o++)
    {
        int m=read();
        for(int i=1;i<=m;i++)
        {
            p[i].x=read();p[i].y=read();
            if(i!=1)f[++cnt]=(line){p[i-1],p[i]};
            if(i==m)f[++cnt]=(line){p[i],p[1]};
        }   
    }
    f[++cnt]=(line){(pot){-inf,-inf},(pot){+inf,-inf}};
    f[++cnt]=(line){(pot){+inf,-inf},(pot){+inf,+inf}};
    f[++cnt]=(line){(pot){+inf,+inf},(pot){-inf,+inf}};
    f[++cnt]=(line){(pot){-inf,+inf},(pot){-inf,-inf}};
    sort(f+1,f+cnt+1,cmp);
    printf("%.3lf",solve(cnt));
    return 0;
}

转载于:https://www.cnblogs.com/Creed-qwq/p/10169605.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值