题目:BZOJ1069、洛谷P4166。
题目大意:
平面上给定n个点,让你选4个点,使得其围成的多边形面积最大。求这个面积。
解题思路:
首先显然的,要使面积最大,则点肯定在凸包上。
然后,由于数据较小(nleqslant 1500),我们枚举四边形对角线的两个点,然后相当于在对角线两侧分别找1个点使得三个点围成的三角形面积最大。
旋转卡壳。
C++ Code:
#include<bits/stdc++.h> int n; struct point{ double x,y,deg; inline point operator+(const point&rhs){return(point){x+rhs.x,y+rhs.y,0};}; inline point operator-(const point&rhs){return(point){x-rhs.x,y-rhs.y,0};}; inline bool operator<(const point&rhs)const{return deg+1e-15<rhs.deg;} }a[2333]; std::vector<point>v; inline double cross(point a,point b){ return a.x*b.y-a.y*b.x; } double anss[2021][2021]; void graham(point*a,int n){ a[++n]=a[1]; v.push_back(a[1]); v.push_back(a[2]); for(int i=3;i<=n;++i){ while(v.size()>1&&cross(v.back()-v[v.size()-2],a[i]-v[v.size()-2])<=0)v.pop_back(); v.push_back(a[i]); } } int main(){ scanf("%d",&n); int down=1; for(int i=1;i<=n;++i){ scanf("%lf%lf",&a[i].x,&a[i].y); if(a[i].y<a[down].y||a[i].y==a[down].y&&a[i].x<a[down].x)down=i; } std::swap(a[1],a[down]); for(int i=2;i<=n;++i)a[i]=a[i]-a[1]; a[1]=(point){0,0}; for(int i=2;i<=n;++i)a[i].deg=atan2(a[i].y,a[i].x); std::sort(a+2,a+n+1); graham(a,n); v.pop_back(); int sz=v.size(); for(int i=0;i<sz;++i)v.push_back(v[i]); // for(auto i:v)printf("%.2f %.2f ,",i.x,i.y); // puts(""); double ans=0; for(int i=0;i<sz;++i){ int np=i+1; for(int j=i+2;j<sz;++j){ while(np+1<j&&cross(v[np]-v[i],v[j]-v[i])<cross(v[np+1]-v[i],v[j]-v[i])+1e-15)++np; anss[i][j]=cross(v[np]-v[i],v[j]-v[i]); } } for(int i=sz-1;~i;--i){ int np=i+1; for(int jj=0;jj+1<i;++jj){ const int j=jj+sz; while(np+1<j&&cross(v[np]-v[i],v[j]-v[i])<cross(v[np+1]-v[i],v[j]-v[i])+1e-15)++np; anss[jj][i]+=cross(v[np]-v[i],v[j]-v[i]); if(anss[jj][i]>ans)ans=anss[jj][i]; } } printf("%.3f ",ans/2); return 0; }