[BZOJ1069]SCOI2007最大土地面積|凸包|旋轉卡殼

    這大概纔是真正的第一題計算幾何了。。首先這四個點肯定在凸包上,所以求出凸包,之後枚舉四邊形的對角線AB,凸包求出來之後點是按逆時針排序的,不妨設B在A的逆時針方向,那麼就在A逆時針轉到B的點之間取一個C點使三角形ABC面積最大,這個用叉積很方便,再在B逆時針轉到A的點之間曲一個D使三角形ABD面積最大,現在ABCD就是以AB爲對角線面積的最大值。。


當A固定B逆時針轉的時候C,D都是逆時針轉的,所以這有點像旋轉卡殼,每一個點只需要O(N)就可以枚舉完答案,所以總複雜度是O(N^2)。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#define ll long long
#define N 2005
#define t1 st[top]
#define t2 st[top-1]
using namespace std;
struct point{
	double x,y;
	point(){}
	point(double x,double y):x(x),y(y){}
} a[N],st[N];
int top,end,i,n;
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;}
bool cmp(point a,point b)
{
	if (a.x!=b.x) return a.x<b.x;else return a.y<b.y;
}
void push(point x)
{
	while (top>=end+2&&(t1-t2)*(x-t1)<=0) top--;
	st[++top]=x;
}
void graham()
{
	end=0;top=0;
	sort(a+1,a+1+n,cmp);
	for (int i=1;i<=n;i++) push(a[i]);
	end=top-1;
	for (int i=n-1;i;i--) push(a[i]);
	top--;
}
int next(int i){return i%top+1;}
double sRC()
{
	double ans=0;
	int l,r;
	for (int i=1;i<=top;i++)
	{
		l=next(i);r=next(i+2);
		for (int j=i+2;j<=top;j++)
		{
			if (r==j)r=next(r);
			while (next(l)!=j&&(st[l]-st[i])*(st[j]-st[i])<(st[next(l)]-st[i])*(st[j]-st[i])) l=next(l);
			while (next(r)!=i&&(st[j]-st[i])*(st[r]-st[i])<(st[j]-st[i])*(st[next(r)]-st[i])) r=next(r);
			ans=max(ans,(st[l]-st[i])*(st[j]-st[i])+(st[j]-st[i])*(st[r]-st[i]));
		}
	}
	return ans;
}
int main()
{
	freopen("1069.in","r",stdin);
	scanf("%d",&n);
	for (i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
	graham();
	printf("%.3lf\n",sRC()/2);
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章