2618: [Cqoi2006]凸多边形

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

题解:
一看就发现是半平面交裸题吧。
反正蒟蒻只想到拆成每条线段求他们的半平面交。
边界打错真是日了
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
#define eps 1e-13
double Maxx=1001.0;
double Minn=-1001.0;
const int N=5100;
struct node{
	double x,y;
}sb[N],ss[N];int pl,cnt=0;
struct node2{
    node p1,p2;
    double angle;
    node2(){}
    node2(double x1,double y1,double x2,double y2)
    {
        p1.x=x1;p1.y=y1;p2.x=x2;p2.y=y2;
    }
    void get_angle()
    {
        angle=atan2(p2.y-p1.y,p2.x-p1.x);
    }
}seg[N],sa[N];int st,ed;
double mulit(node p1,node p2,node p0)
{
    double x1=p1.x-p0.x,y1=p1.y-p0.y;
    double x2=p2.x-p0.x,y2=p2.y-p0.y;
    return x1*y2-x2*y1;
}
bool satify(node x,node2 y)
{
    if(mulit(x,y.p2,y.p1)<=eps) return true;return false;
}
bool cmp(node2 x,node2 y)
{
    if(x.angle<y.angle) return true;
    if(fabs(x.angle-y.angle)<eps&&satify(x.p1,y)==true) return true;
    return false;
}
node jd(node2 x,node2 y)
{
    node p1=x.p1,p2=x.p2,p3=y.p1,p4=y.p2,p;
    double t1=mulit(p1,p4,p3);
    double t2=mulit(p2,p4,p3);
    p.x=(t1*p2.x-t2*p1.x)/(t1-t2);
    p.y=(t1*p2.y-t2*p1.y)/(t1-t2);
    return p;
}
void work()
{
    sort(seg+1,seg+cnt+1,cmp);
    int tp=1;
    for(int i=2;i<=cnt;i++)
    if(seg[i].angle-seg[tp].angle>eps) seg[++tp]=seg[i];
    cnt=tp;
    sa[1]=seg[1];sa[2]=seg[2];
    st=1,ed=2;
    for(int i=3;i<=cnt;i++)
    {
        while(st<ed&&satify(jd(sa[ed],sa[ed-1]),seg[i])==false) ed--;
        while(st<ed&&satify(jd(sa[st],sa[st+1]),seg[i])==false) st++;
        sa[++ed]=seg[i];
    }
    while(st<ed&&satify(jd(sa[ed],sa[ed-1]),seg[st])==false) ed--;
    while(st<ed&&satify(jd(sa[st],sa[st+1]),seg[ed])==false) st++;
    if(ed-st+1<=2){printf("0.000");return;}
    pl=0;
    for(int i=st;i<ed;i++) sb[++pl]=jd(sa[i],sa[i+1]);
    sb[++pl]=jd(sa[ed],sa[st]);
    double ans=0.000;
    for(int i=3;i<=pl;i++) ans+=mulit(sb[i-1],sb[i],sb[1]);
    printf("%0.3lf",fabs(ans)/2.000);
}
int n,m;
int main()
{
	seg[++cnt]=node2(Minn,Minn,Maxx,Minn);seg[1].get_angle();
    seg[++cnt]=node2(Maxx,Minn,Maxx,Maxx);seg[2].get_angle();
    seg[++cnt]=node2(Maxx,Maxx,Minn,Maxx);seg[3].get_angle();
    seg[++cnt]=node2(Minn,Maxx,Minn,Minn);seg[4].get_angle();
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&m);
		for(int j=1;j<=m;j++)
		{
			scanf("%lf%lf",&ss[j].x,&ss[j].y);
		}
		for(int j=1;j<m;j++)
		seg[++cnt]=node2(ss[j].x,ss[j].y,ss[j+1].x,ss[j+1].y),seg[cnt].get_angle();
		seg[++cnt]=node2(ss[m].x,ss[m].y,ss[1].x,ss[1].y),seg[cnt].get_angle();
	}
	work();
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值