【BZOJ1069】【SCOI2007】最大土地面积
题目大意:给定有n个点的点集,求该点集中任意四个点所构成的四边形中面积最大四边形的面积。
我们不难想到(不难yy出来),面积最大的四边形的四个顶点一定所给定的点集所构成的凸包上。我们求出给定点集的集合后,枚举一条对角线,由该对角线将凸包分为上下两部分,分别求出两个面积最大的三角形,面积加起来然后更新即可。对于每一次枚举,对角线的长度是固定的,由于凸包具有某些特殊性性质,我们可以通过三分求出面积最大的三角形的顶点,然后就OK了。
时间复杂度:$O(n^{2}*log(n))$。
刚开始因为我写得太挫,导致被卡了常数(1.1s),后来将原先两点距离公式+海伦公式求三角形面积法改为了铅锤法,从1100+ms降低至450ms才AC。
PS:此题其实可以用二分,三分有点多余(但是我不想改了啦啦啦)。
1 #include<bits/stdc++.h> 2 #define M 100000 3 #define y0 y123 4 #define pi acos(-1) 5 using namespace std; 6 double x0,y0=1e20; 7 struct node{ 8 double x,y; node(){x=y=0;} 9 node(double xx,double yy){x=xx; y=yy;} 10 friend bool operator <(node a,node b){ 11 double ap1=atan((a.y)/(a.x)); 12 double ap2=atan((b.y)/(b.x)); 13 if(ap1<0) ap1=pi+ap1; 14 if(ap2<0) ap2=pi+ap2; 15 return ap1<ap2; 16 } 17 friend node operator -(node a,node b){return node(a.x-b.x,a.y-b.y);} 18 friend double operator *(node a,node b){return a.x*b.y-a.y*b.x;} 19 }a[M],s[M]; 20 double dis(node a,node b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));} 21 double gets(int i,int j,int k){ 22 node A=s[i],B=s[j],C=s[k]; 23 double d,K,b; 24 if(A.x>B.x) swap(A,B); 25 if(A.x>C.x) swap(A,C); 26 if(B.x>C.x) swap(B,C); 27 K=(A.y-C.y)/(A.x-C.x); b=A.y-A.x*K; 28 d=K*B.x+b; 29 return abs(d-B.y)*(C.x-A.x); 30 } 31 32 int main(){ 33 int n,use=0; scanf("%d",&n); 34 for(int i=1;i<=n;i++){ 35 double x,y; cin>>x>>y; 36 a[i]=node(x,y); 37 if(y<a[1].y) swap(a[1],a[i]); 38 } 39 for(int i=2;i<=n;i++) a[i]=a[i]-a[1]; 40 a[1]=node(0,0); 41 sort(a+2,a+n+1); a[n+1]=a[1]; 42 s[++use]=a[1]; s[++use]=a[2]; 43 for(int i=3;i<=n+1;i++){ 44 while(use>1&&(a[i]-s[use-1])*(s[use]-s[use-1])>0) use--; 45 if(i<=n) s[++use]=a[i]; 46 } 47 n=use; double maxn=0; 48 for(int i=1;i<=n;i++) s[i+n]=s[i]; 49 for(int i=1;i<=n;i++) 50 for(int j=i+1;j<=n;j++){ 51 double sup=0,sdn=0,now=0; 52 int l=i,r=j; 53 while(r-l>3){ 54 int mid1=(l+l+r)/3,mid2=(l+r+r)/3; 55 if(gets(i,j,mid1)>gets(i,j,mid2)) r=mid2; 56 else l=mid1; 57 } 58 for(int k=l;k<=r;k++) sup=max(sup,gets(i,j,k)); 59 l=j; r=n+i-1; 60 while(r-l>3){ 61 int mid1=(l+l+r)/3,mid2=(l+r+r)/3; 62 if(gets(i,j,mid1)>gets(i,j,mid2)) r=mid2; 63 else l=mid1; 64 } 65 for(int k=l;k<=r;k++) sdn=max(sdn,gets(i,j,k)); 66 maxn=max(maxn,sup+sdn); 67 } 68 printf("%.3lf\n",maxn/2.); 69 }