【BZOJ 1069】 凸包+旋转卡壳

1069: [SCOI2007]最大土地面积

Description

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

Input

  第1行一个正整数N,接下来N行,每行2个数x,y,表示该点的横坐标和纵坐标。

Output

  最大的多边形面积,答案精确到小数点后3位。

Sample Input

5
0 0
1 0
1 1
0 1
0.5 0.5

Sample Output

1.000

HINT

数据范围 n<=2000, |x|,|y|<=100000

 

【分析】

  这个叫旋转 qia 壳?

  好吧,去偷个gif回来。。

  

  其实还是形象生动,旋转卡壳是算点到线段的距离的,就是两条线扫啊扫,有点单调的意思。

  这题里,枚举四边形的对角线,然后两边找离这条线段的最远的点,可以证明这些点都是在凸包上的(好像很明显??)

  就直接在凸包上找,假设已经枚举了线段x-y,现在枚举x-y+1,卡壳线不断逆时针旋转就可以了(我的打法是逆时针旋转),因为前面去掉的点以后肯定也没有用的,嗯。。

  然后,这里要用到平面差积,差积的值是有正负的,所以用差积算面积的时候要小心一点。然后也是用差积比较斜率的。。

 

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<iostream>
 6 using namespace std;
 7 #define Maxn 2010
 8 
 9 int n;
10 
11 const double eps=0.000001;
12 struct P{double x,y;}a[Maxn],c[Maxn];
13 int len;
14 
15 double mymax(double x,double y) {return x>y?x:y;}
16 double myabs(double x) {return x<0?-x:x;}
17 
18 P operator - (P x,P y)
19 {
20     P tt;
21     tt.x=x.x-y.x;tt.y=x.y-y.y;
22     return tt;
23 }
24 
25 int dcmp(double x)
26 {  
27     if(myabs(x)<eps) return 0;
28    else return x<0?-1:1;
29 }
30 bool cmp(P x,P y) {return dcmp(x.x-y.x)==0?(x.y<y.y):(x.x<y.x);}
31 double Dot(P x,P y) {return x.x*y.x+x.y*y.y;}
32 double Cross(P x,P y) {return x.x*y.y-x.y*y.x;}
33 
34 void chull()
35 {
36     sort(a+1,a+1+n,cmp);
37     len=0;    
38     for(int i=1;i<=n;i++)
39     {
40         while(len>1&&Cross(c[len]-c[len-1],a[i]-c[len])<=0) len--;
41         c[++len]=a[i];
42     }
43     int k=len;
44     for(int i=n-1;i>=1;i--)
45     {
46         while(len>k&&Cross(c[len]-c[len-1],a[i]-c[len])<=0) len--;
47         c[++len]=a[i];
48     }
49     len--;
50 }
51 
52 double ans=0;
53 void RC()//rotating calipers
54 {
55     for(int i=1;i<=len;i++)
56     {
57         int k1=i%len+1,k2=(i+2)%len+1;//两边一起做旋转卡壳
58         for(int j=i+2;j<=len;j++)
59         {
60             while(k1%len+1!=j&&Cross(c[k1+1]-c[i],c[j]-c[i])>Cross(c[k1]-c[i],c[j]-c[i])) 
61                 k1=k1%len+1;
62             while(k2%len+1!=i&&Cross(c[j]-c[i],c[k2+1]-c[i])>Cross(c[j]-c[i],c[k2]-c[i]))
63                 k2=k2%len+1;
64             ans=mymax(ans,Cross(c[j]-c[i],c[k2]-c[i])+Cross(c[k1]-c[i],c[j]-c[i]));
65         }
66     }
67 }
68 
69 
70 int main()
71 {
72     scanf("%d",&n);
73     for(int i=1;i<=n;i++)
74     {
75         scanf("%lf%lf",&a[i].x,&a[i].y);
76     }
77     chull();
78     RC();
79     printf("%.3lf\n",ans/2);
80     return 0;
81 }
View Code

 

2016-12-10 09:44:52

 


 

有一篇很好的讲旋转卡壳的博:

http://blog.csdn.net/hanchengxi/article/details/8639476

 

 

posted @ 2016-12-10 09:39  konjak魔芋  阅读(340)  评论(0编辑  收藏  举报