求半平面交的面积模板

题意

在一个有限大(-10 0000<=x,y<=10 0000)的平面坐标系上有n个半平面(注意有限的),每个半平面给出一条有向线段(x1,y1)——>(x2,y2)。
每个半平面的有效区域都是左侧。求这n个半平面的交的面积。

题解

半平面交的模板
以前偷懒,学了个 (n2) ( n 2 ) 的,但是已经忘了啊
于是今天趁没网学了个 nlogn 的 n l o g n
模板调了一个多小时QAQ
现在才会啊
感觉也不难。。
就这样,存下板子吧。。
教程我就不写了

CODE:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const double MAX=100001;
const int N=20005;
const double eps=1e-8;
int n;
struct pnt{double x,y;};
struct qq
{
    pnt x,y;
    double angle;
}s[N];int tot=0;
void add (double x1,double y1,double x2,double y2)
{
    tot++;
    s[tot].x.x=x1;
    s[tot].x.y=y1;
    s[tot].y.x=x2;
    s[tot].y.y=y2;
    /*s[tot].x=pnt{x1,y1};
    s[tot].y=pnt{x2,y2};*/
    s[tot].angle=atan2(y2-y1,x2-x1);
}
double mul (pnt x,pnt y,pnt z)
{
    double x1=x.x-z.x,x2=y.x-z.x;
    double y1=x.y-z.y,y2=y.y-z.y;
    return x1*y2-x2*y1;
}
bool cmp (qq x,qq y)
{
    if (abs(x.angle-y.angle)<eps)
        return mul(x.y,y.y,x.x)<-eps;
    return x.angle<y.angle;
}
int q[N];
pnt JD(qq x,qq y)//两条直线的交点 
{
    double s1=mul(x.y,y.x,x.x);
    double s2=mul(x.y,x.x,y.y);
    pnt xx;
    xx.x=(y.x.x*s2+y.y.x*s1)/(s1+s2);
    xx.y=(y.x.y*s2+y.y.y*s1)/(s1+s2);
    return xx;
}
bool check (qq x,qq a,qq b)//a,b的交点是不是在x的右侧 
{
    pnt xx=JD(a,b);
    return mul(x.y,xx,x.x)<-eps;
}
pnt ans[N];
void solve ()
{
    sort(s+1,s+1+tot,cmp);

    n=1;
    for (int u=2;u<=tot;u++)
        if (abs(s[u].angle-s[n].angle)>eps)
            s[++n]=s[u];
    int st=1,ed=2;
    q[1]=1;q[2]=2;
    for (int u=3;u<=n;u++)
    {
        while (st<ed&&check(s[u],s[q[ed]],s[q[ed-1]])) ed--;    
        while (st<ed&&check(s[u],s[q[st]],s[q[st+1]])) st++;
        q[++ed]=u;
    }

    while (st<ed&&check(s[q[st]],s[q[ed]],s[q[ed-1]])) ed--;
    while (st<ed&&check(s[q[ed]],s[q[st]],s[q[st+1]])) st++;
    q[++ed]=q[st];
    n=0;
    for (int u=st;u<ed;u++)
        ans[++n]=JD(s[q[u]],s[q[u+1]]); 
    /*for (int u=1;u<=n;u++)
        printf("YES:%lf %lf\n",ans[u].x,ans[u].y);*/
}
int main()
{
    scanf("%d",&n);
    for (int u=1;u<=n;u++)
    {
        double x1,y1,x2,y2;
        scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
        add(x1,y1,x2,y2);
    }
    add(-MAX,-MAX,MAX,-MAX);
    add(MAX,-MAX,MAX,MAX);
    add(MAX,MAX,-MAX,MAX);
    add(-MAX,MAX,-MAX,-MAX);
    solve();
    if (n<=2)
    {
        printf("0.0\n");
        return 0;
    }
    double lalal=0;
    for (int u=3;u<=n;u++)
        lalal=lalal+mul(ans[u],ans[u-1],ans[1]);
    printf("%.1lf\n",abs(lalal)/2);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值