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

 

posted @ 2018-07-15 10:26  HocRiser  阅读(245)  评论(0编辑  收藏  举报