POJ - 1279 Art Gallery 半平面交学习 求内核面积

题目链接:https://vjudge.net/problem/POJ-1279

半平面交学习:点击查看

题解:求内核面积,半平面交,存模板

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double eps=1e-8;
int sgn(double x)
{
	if(fabs(x)<eps)return 0;
	if(x<0)return -1;
	return 1;
}
struct Point{
	double x,y;
	Point(){
	}
	Point(double x_,double y_)
	{
		x=x_;
		y=y_;
	}
	Point operator -(const Point &b)const
	{
		return Point(x-b.x,y-b.y);
	}
	double operator ^(const Point &b)const
	{
		return x*b.y-y*b.x;
	}
	double operator *(const Point &b)const
	{
		return x*b.x+y*b.y;
	}
};
struct Line{
	Point s,e;
	double k;
	Line(){
	}
	Line(Point s_,Point e_)
	{
		s=s_;
		e=e_;
		k=atan2(e.y-s.y,e.x-s.x);
	}
	Point operator &(const Line &b)const
	{
		Point res=s;
		double t=((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));
		res.x += (e.x-s.x)*t;
		res.y += (e.y-s.y)*t;
		return res;
	}
	
};
bool HPIcmp(Line a,Line b)
{
	if(fabs(a.k-b.k)>eps)return a.k<b.k;
	else return ((a.s-b.s)^(b.e-b.s))<0;
}
Line Q[1510];
void HPI(Line line[],int n,Point res[],int &resn)
{
	int tot=n;
	sort(line,line+n,HPIcmp);
	tot=1;
	for(int i=1;i<n;i++)    // 去掉右边的线段,保留左边的线段。
	{
		if(fabs(line[i].k-line[i-1].k)>eps)
			line[tot++]=line[i];
	}
	int head=0,tail=1;
	Q[0]=line[0];
	Q[1]=line[1];
	resn=0;
	for(int i=2;i<tot;i++)
	{
		if(fabs((Q[tail].e-Q[tail].s)^(Q[tail-1].e-Q[tail-1].s)) < eps ||
		fabs((Q[head].e-Q[head].s)^(Q[head+1].e-Q[head+1].s)) < eps )
			return;
		while(head<tail && (((Q[tail]&Q[tail-1]) - line[i].s) ^ (line[i].e-line[i].s)) > eps)
			tail--;
		while(head<tail && (((Q[head]&Q[head+1]) - line[i].s) ^ (line[i].e-line[i].s)) > eps)
			head++;
		Q[++tail]=line[i];
	}
	while(head<tail && (((Q[tail]&Q[tail-1]) - Q[head].s) ^ (Q[head].e-Q[head].s)) > eps)
		tail--;
	while(head<tail && (((Q[head]&Q[head+1]) - Q[tail].s) ^ (Q[tail].e-Q[tail].s)) > eps)
		tail--;
	while(tail<=head+1)return;
	for(int i=head;i<tail;i++)  // 保存内核点 
		res[resn++]=Q[i]&Q[i+1];
	res[resn++]=Q[head]&Q[tail];
} 
double CalcArea(Point p[],int n)
{
	double ans=0;
	for(int i=0;i<n;i++)
	{
		ans+=(p[i]^p[(i+1)%n])/2;
	}
	return ans;
}
int main()
{
	int T;
	Point p[1510];
	Line line[1510];
	scanf("%d",&T);
	while(T--)
	{
		int n;
		
		scanf("%d",&n);
		for(int i=0;i<n;i++)
			scanf("%lf%lf",&p[i].x,&p[i].y);
		if(CalcArea(p,n)<0)  //  判断给的点的顺序,使其为逆序 
			reverse(p,p+n);
		for(int i=0;i<n;i++)
			line[i]=Line(p[i],p[(i+1)%n]);
		int resn=0;
		HPI(line,n,p,resn);
	//	cout<<resn<<endl;
		printf("%.2f\n",CalcArea(p,resn));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/mmk27_word/article/details/89791504