【BZOJ1069】【SCOI2007】最大土地面积 计算几何 凸包

凸包模板题。。。

我用的是一种叫Graham的方法,主要思想是以最下最左的点作为原点,将其余各点按照极角排序(用向量的叉积实现),之后用栈维护新点永远在凸包最后两点的射线右边即可。

用反证法不难证明四个点一定全在凸包上(不然一定存在一个比已知四边形更大的四边形),枚举对角线将四边形隔成两个三角形,旋转卡壳维护两个三角形最大面积即可。

#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define maxn 2005
struct P{double x,y;}a[maxn],s[maxn];
int top,n;
double dis(P x,P y)
{
	return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));
}
P operator +(P x,P y)
{
	return (P){x.x+y.x,x.y+y.y};
}
P operator -(P x,P y)
{
	return (P){x.x-y.x,x.y-y.y};
}
double operator *(P x,P y)
{
	return x.x*y.y-x.y*y.x;
}
bool operator < (P x,P y)
{
	double t=(x-a[1])*(y-a[1]);
	if(t==0)return dis(x,a[1])<dis(y,a[1]);
	return t>0;
}
void Init()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%lf%lf",&a[i].x,&a[i].y);
	}
}
void graham()
{
	top=1;
	for(int i=2;i<=n;i++)if((a[i].x<a[top].x)||(a[i].x==a[top].x && a[i].y<a[top].y))top=i;
	if(top!=1)swap(a[1],a[top]);
	sort(a+2,a+1+n);
	top=2; s[1]=a[1]; s[2]=a[2];
	for(int i=3;i<=n;i++)
	{
		while(top>1 && (s[top]-s[top-1])*(a[i]-s[top-1])<=0)top--;
		s[++top]=a[i];
	}
	return ;
}
void work()
{
	double ans=0;
	int nc,nd;
	for(int i=1;i<=top;i++)
	{
		nc=i+1; nd=i+3;
		for(int j=i+2;j<=top;j++)
		{
			while(nc%top+1!=j && (s[nc%top+1]-s[nc])*(s[j]-s[i])>=0)
			{
				nc=nc%top+1;
			}
			while(nd%top+1 !=i && (s[nd%top+1]-s[nd])*(s[i]-s[j])>=0)
			{
				nd=nd%top+1;
			}
			ans=max(ans,(s[nc]-s[i])*(s[j]-s[i])+(s[j]-s[i])*(s[nd]-s[i]));
		}
	}
	ans=ans/2.0;
	printf("%.3lf\n",ans);
	return ;
}
int main()
{
	freopen("in.txt","r",stdin);
	Init();
	graham();
	work();
	return 0;
}


你可能感兴趣的:(模板题,凸包,计算几何)