【CQOI2006】【BZOJ2618】凸多边形

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

拆出边半平面交一下然后做凸包求面积.
我并不知道别的做法要怎么做…但是感觉似乎有
看数据范围半平面交不写排序增量暴力就能过
说不定当时重庆考场上就是给的暴力

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXDBL 1e20
#define eps 1e-9
#define MAXN 1010
using namespace std;
int n,m,cnt,num;
double ans;
struct Point
{
    double x,y;
}s[MAXN],Hull[MAXN];
Point operator -(Point a,Point b)
{
    return (Point){a.x-b.x,a.y-b.y};
}
double operator *(Point a,Point b)
{
    return a.x*b.y-a.y*b.x;
}
struct line
{
    Point a,b;
    double k;
    bool operator <(const line& A)const
    {
        if (k!=A.k) return k<A.k;
        return (b-a)*(A.b-a)>0;
    }
}que[MAXN],l[MAXN];
int head=1,tail;
Point get_inter(line A,line B)
{
    double tmp1=(B.b-A.a)*(A.b-A.a),tmp2=(A.b-A.a)*(B.a-A.a);
    double t=tmp1/(tmp1+tmp2);
    return (Point){B.b.x+t*(B.a.x-B.b.x),B.b.y+t*(B.a.y-B.b.y)};
}
bool check(line A,line B,line C)//On_right
{
    Point Inter=get_inter(A,B);
    return (C.b-C.a)*(Inter-C.a)<0;
}
void Calc()
{
    if (cnt<3)  return;
    for (int i=1;i<=cnt;i++)    ans+=Hull[i]*Hull[i+1];
    ans=fabs(ans)/2;
}
int main()
{
    scanf("%d",&n);
    while (n--)
    {
        scanf("%d",&m);
        for (int i=1;i<=m;i++)  scanf("%lf%lf",&s[i].x,&s[i].y);s[m+1]=s[1];
        for (int i=1;i<=m;i++)  l[++cnt].a=s[i],l[cnt].b=s[i+1];
    }
    for (int i=1;i<=cnt;i++)    l[i].k=atan2(l[i].b.y-l[i].a.y,l[i].b.x-l[i].a.x);
    sort(l+1,l+cnt+1);
    for(int i=1;i<=cnt;i++)
    {
        if(l[i].k!=l[i-1].k)    num++;
        l[num]=l[i];
    }
    que[++tail]=l[1];que[++tail]=l[2];
    for (int i=3;i<=num;i++)
    {
        while (head<tail&&check(que[tail-1],que[tail],l[i]))    tail--;
        while (head<tail&&check(que[head+1],que[head],l[i]))    head++;
        que[++tail]=l[i];
    }
    while (head<tail&&check(que[tail-1],que[tail],que[head]))   tail--;
    while (head<tail&&check(que[head+1],que[head],que[tail]))   head++;
    que[tail+1]=que[head];cnt=0;
    for (int i=head;i<=tail;i++)    Hull[++cnt]=get_inter(que[i],que[i+1]);
    Hull[cnt+1]=Hull[1];
    Calc();
    printf("%.3f",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值