【BZOJ2618】[Cqoi2006]凸多边形 半平面交

【BZOJ2618】[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

HINT

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

题解:半平面交板子题,刷板子~

注意先弹t后弹h。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=510;
const double eps=1e-9;
struct point
{
	double x,y;
	point() {}
	point(double a,double b) {x=a,y=b;}
	point operator + (const point &a) const {return point(x+a.x,y+a.y);}
	point operator - (const point &a) const {return point(x-a.x,y-a.y);}
	double operator * (const point &a) const {return x*a.y-y*a.x;}
	point operator * (const double &a) const {return point(a*x,a*y);}
}p[maxn];
int m,n,h,t,np,q[maxn];
struct line
{
	point p,v;
	double a;
	line() {}
	line(point x,point y) {p=x,v=y,a=atan2(v.y,v.x);}
}l[maxn];
point getp(line l1,line l2)
{
	point u=l1.p-l2.p;
	double temp=(l2.v*u)/(l1.v*l2.v);
	return l1.p+l1.v*temp;
}
bool onlft(line a,point b)
{
	return a.v*(b-a.p)>eps;
}
bool cmp(line a,line b)
{
	if(fabs(a.a-b.a)<eps)	return onlft(a,b.p);
	return a.a<b.a;
}
void HPI()
{
	sort(l+1,l+n+1,cmp);
	int i,j;
	for(i=2,j=1;i<=n;i++)	if(fabs(l[i].a-l[j].a)>eps)	l[++j]=l[i];
	n=j,h=t=q[1]=1;
	for(i=2;i<=n;i++)
	{
		while(h<t&&onlft(l[i],getp(l[q[t]],l[q[t-1]])))	t--;
		while(h<t&&onlft(l[i],getp(l[q[h]],l[q[h+1]])))	h++;
		q[++t]=i;
	}
	while(h<t&&onlft(l[q[h]],getp(l[q[t]],l[q[t-1]])))	t--;
	while(h<t&&onlft(l[q[t]],getp(l[q[h]],l[q[h+1]])))	h++;
	q[++t]=q[h];
	for(i=h,np=0;i<t;i++)	p[++np]=getp(l[q[i]],l[q[i+1]]);
}
double getarea()
{
	if(np<3)	return 0;
	double ret=0;
	for(int i=2;i<=np;i++)	ret+=p[i-1]*p[i];
	ret+=p[np]*p[1];
	return fabs(ret/2);
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret*f;
}
int main()
{
	int i,j,a;
	m=rd();
	for(i=1;i<=m;i++)
	{
		a=rd();
		for(j=1;j<=a;j++)	p[j].x=rd(),p[j].y=rd();
		for(j=1;j<=a;j++)	l[++n]=line(p[j],p[j]-p[j%a+1]);
	}
	HPI();
	printf("%.3lf\n",getarea());
	return 0;
}//8 0 0 0 2 1 2 1 1 2 1 2 2 3 2 3 0

 

posted @ 2017-09-10 11:25  CQzhangyu  阅读(290)  评论(0编辑  收藏  举报