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;
}