[BZOJ1069][SCOI2007]最大土地面积(水平扫描法求凸包+旋转卡壳)
题意:在某块平面土地上有N个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成。
的多边形面积最大。n<=2000。
先求凸包,再枚举对角线,随着对角线的斜率上升,另外两个点的在凸包上的位置也是单调的。
水平扫描法:先将所有点按x排序,然后从左往右边扫边求出上凸壳,然后从右往左扫出下凸壳。最后会发现a[tot]=a[1]。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 using namespace std; 5 6 const int N=2010; 7 int n,r,p1,p2,q[N]; 8 double ans; 9 struct P{ 10 double x,y; 11 bool operator <(const P &b)const{ return x==b.x ? y<b.y : x<b.x; } 12 P operator -(const P &b)const{ return (P){x-b.x,y-b.y}; } 13 double operator *(const P &b)const{ return x*b.y-y*b.x; } 14 }a[N]; 15 double cj(int x,int y,int z){ return (a[x]-a[y])*(a[z]-a[y]); } 16 17 int main(){ 18 freopen("bzoj1069.in","r",stdin); 19 freopen("bzoj1069.out","w",stdout); 20 scanf("%d",&n); 21 rep(i,1,n) scanf("%lf%lf",&a[i].x,&a[i].y); 22 sort(a+1,a+n+1); 23 rep(i,1,n){ 24 while (r>1 && cj(q[r],q[r-1],i)>=0) r--; 25 q[++r]=i; 26 } 27 int rr=r; 28 for (int i=n-1; i>=1; i--){ 29 while (r>rr && cj(q[r],q[r-1],i)>=0) r--; 30 q[++r]=i; 31 } 32 rep(i,1,r-1){ 33 int p1=i+1,p2=i+3; 34 rep(j,i+2,r-2){ 35 while (p1<j-1 && cj(q[j],q[i],q[p1])<=cj(q[j],q[i],q[p1+1])) p1++; 36 while (p2<=j || (p2<r-1 && cj(q[p2],q[i],q[j])<=cj(q[p2+1],q[i],q[j]))) p2++; 37 ans=max(ans,cj(q[j],q[i],q[p1])+cj(q[p2],q[i],q[j])); 38 } 39 } 40 printf("%.3lf\n",ans/2); 41 return 0; 42 }