[bzoj2618][半平面交][Cqoi2006]凸多边形

2618: [Cqoi2006]凸多边形

Time Limit: 5 Sec Memory Limit: 128 MB
Submit: 1920 Solved: 955
[Submit][Status][Discuss]
Description

逆时针给出n个凸多边形的顶点坐标,求它们交的面积。例如n=2时,两个凸多边形如下图:

则相交部分的面积为5.233。
Input

第一行有一个整数n,表示凸多边形的个数,以下依次描述各个多边形。第i个多边形的第一行包含一个整数mi,表示多边形的边数,以下mi行每行两个整数,逆时针给出各个顶点的坐标。

Output

输出文件仅包含一个实数,表示相交部分的面积,保留三位小数。

Sample Input

2

6

-2 0

-1 -2

1 -2

2 0

1 2

-1 2

4

0 -3

1 -1

2 2

-1 0

Sample Output

5.233
HINT

100%的数据满足:2<=n<=10,3<=mi<=50,每维坐标为[-1000,1000]内的整数

Source

sol:

具体的可以看这个博客。
https://www.cnblogs.com/XDJjy/archive/2013/09/13/3320205.html

那这些都是把点确定好的,要是只给出了若干个半平面形如ax+by+c>=0呢?首先你随便取一个点,>=0时向量取b,-a,<=0时向量取-b,a。这个从

其实就是和求凸包的过程类似。就是判断两个向量的左右手时不要错就行了。。

#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
using namespace std;
typedef double s64;
int n,m;
inline int read()
{
    char c;
    int res,flag=0;
    while((c=getchar())>'9'||c<'0') if(c=='-')flag=1;
    res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=(res<<3)+(res<<1)+c-'0';
    return flag?-res:res;
}
const int N=510;
struct P
{
    s64 x,y;
    friend inline P operator +(const P &a,const P &b) {
        return (P){a.x+b.x,a.y+b.y};
    }
    friend inline P operator -(const P &a,const P &b) {
        return (P){a.x-b.x,a.y-b.y};
    }
    friend inline P operator *(const P &a,s64 b) {
        return (P){a.x*b,a.y*b};
    }
    friend inline s64 operator *(const P &a,const P &b) {
        return a.x*b.y-a.y*b.x;
    }
    friend inline s64 operator /(const P &a,const P &b) {
        return a.x*b.x+a.y*b.y;
    }
}a[N];
struct L
{
    P a,b,v;
    s64 ang;
    friend inline bool operator <(const L &a,const L &b)
    {
        return a.ang<b.ang||a.ang==b.ang&&a.v*(b.b-a.a)>0;
    }
    friend inline P inter(const L &a,const L &b)
    {
        P nw=b.a-a.a;
        s64 tt=(nw*a.v)/(a.v*b.v);
        return b.a+b.v*tt;
    }
    friend inline bool jud(const P &a,const L &b)
    {
        return b.v*(a-b.a)<0;
    }
}l[N],q[N];
int cnt;
int tot;
inline void solve()
{
    n=read();
    for(int i=1;i<=n;++i)
    {
        m=read();
        P st,la,nw;
        scanf("%lf%lf",&st.x,&st.y);
        la=st;
        for(int j=2;j<=m;++j)
        {
            scanf("%lf%lf",&nw.x,&nw.y);
            l[++cnt]=(L){la,nw,nw-la};
            la=nw;
        }
        l[++cnt]=(L){la,st,st-la};
    }
    for(int i=1;i<=cnt;++i) l[i].ang=atan2(l[i].v.y,l[i].v.x);
    sort(l+1,l+1+cnt);
    for(int i=1;i<=cnt;++i)
    {
        if(l[i].ang!=l[i-1].ang) ++tot;
        l[tot]=l[i];
    }
    cnt=tot;
    tot=0;
    int L=1,R=2;
    q[1]=l[1];q[2]=l[2];
    for(int i=3;i<=cnt;++i)
    {
        while(L<R&&jud(inter(q[R-1],q[R]),l[i])) --R;
        while(L<R&&jud(inter(q[L+1],q[L]),l[i])) ++L;
        q[++R]=l[i];
    }
    while(L<R&&jud(inter(q[R-1],q[R]),q[L])) --R;
    while(L<R&&jud(inter(q[L+1],q[L]),q[R])) ++L;
    q[R+1]=q[L];
    for(int i=L;i<=R;++i) a[++tot]=inter(q[i],q[i+1]);
}
s64 ans;
inline void calc()
{
    for(int i=1;i<tot;++i) ans+=a[i]*a[i+1];
    ans+=a[tot]*a[1];
    if(tot<3) ans=0;
    printf("%.3lf",ans/2); 
}

int main()
{
//  freopen("2618.in","r",stdin);
//  freopen(".out","w",stdout);
    solve();
    calc();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值