【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.5Sample Output
1.000HINT
数据范围 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 }
2016-12-10 09:44:52
有一篇很好的讲旋转卡壳的博:
http://blog.csdn.net/hanchengxi/article/details/8639476