bzoj 1069 凸包+旋转卡壳

题目大意

在某块平面土地上有N个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成
的多边形面积最大。

分析

枚举对角线的一个端点
另一个端点开始转
转的时候求出对角线左边面积最大的三角形,右边面积最大的三角形
三角形面积\(=\)对角线长度\(*\)
\(=\)两条平行线间任意两点距离
过对角线做两条平行线,对着凸包夹一夹
可以发现这实际上就是一个旋转卡壳
\(O(n^2)\)

solution

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
typedef long double db ;
using namespace std;
const int M=2007;

struct pt{
	db x,y;
	pt(db xx=0.0,db yy=0.0){x=xx;y=yy;}
}p[M],s[M];
pt operator -(pt x,pt y){return pt(x.x-y.x,x.y-y.y);}
pt operator +(pt x,pt y){return pt(x.x+y.x,x.y+y.y);}
bool operator <(pt x,pt y){if(x.y!=y.y)return x.y<y.y; return x.x<y.x;}
db cross(pt x,pt y){
	return x.x*y.y-x.y*y.x;
}
db dot(pt x,pt y){
	return x.x*y.x+x.y*y.y;
}
db area(pt x,pt y,pt z){
	return cross(y-x,z-x);
}
db length(pt x){
	return sqrt(dot(x,x));
};
db shadow(pt x,pt to){
	return dot(x,to)/length(to);
}

bool cmp(pt x,pt y){//ÄæʱÕ뼫½ÇÅÅÐò 
	db tp=area(p[1],x,y);
	if(tp==0) return length(x-p[1])<length(y-p[1]);
	return tp>0;	
}

int n;

int tot;

void convex(){
	int ii=1,i;
	for(i=1;i<=n;i++) if(p[i]<p[ii]) ii=i;
	swap(p[1],p[ii]);
	sort(p+2,p+n+1,cmp);
	
	s[tot=1]=p[1];
	for(i=2;i<=n;i++){
		while(tot>1&&area(s[tot-1],s[tot],p[i])<=0) tot--;//  <=  
		s[++tot]=p[i];
	} 
}

int main(){
	int i,j,k,p1,p2;
	db x,y;
	scanf("%d",&n);
 	for(i=1;i<=n;i++){
 		scanf("%Lf%Lf",&x,&y);
 		p[i]=pt(x,y);
	}
	
	convex();
	
	db ans=0;
	for(i=1;i<tot;i++){
		p1=i,p2=i+1;
		for(j=i+1;j<=tot;j++){
			while(area(s[i],s[p1],s[j])<area(s[i],s[p1%tot+1],s[j])) p1=p1%tot+1;
			while(area(s[i],s[j],s[p2])<area(s[i],s[j],s[p2%tot+1])) p2=p2%tot+1;
			ans=max(ans,area(s[i],s[p1],s[j])+area(s[i],s[j],s[p2]));
		}
	}
	
	printf("%.3Lf\n",ans/2.0);

	return 0;
}
posted @ 2017-02-22 15:54  _zwl  阅读(134)  评论(0编辑  收藏  举报