[bzoj1069][SCOI2007]最大土地面积
给定n个点,你要选出4个点使得面积最大。n<=2000
题解:求凸包,然后旋转卡壳,根据某证明,对踵点不会超过3n/2,所以对于每一对对踵点暴力找最远点就可以了。
复杂度n^2
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; double ans=0; int n,rt=1,q[2005],top=0; struct P{double x,y;}s[2005]; double cross(P x,P y,P z) { double x0=y.x-x.x,xx=z.x-x.x,y0=y.y-x.y,yy=z.y-x.y; return x0*yy-xx*y0; } double area(P x,P y,P z){return fabs(cross(x,y,z))/2.00000;} bool cmp(P x,P y){return cross(s[rt],x,y)>0;} void calc(int s1,int s2) { double mx1=0,mx2=0;if(s1>s2)swap(s1,s2); for(int i=s1+1;i<s2;i++)mx1=max(mx1,area(s[s1],s[s2],s[i])); for(int i=s2+1;i<=n;i++)mx2=max(mx2,area(s[s1],s[s2],s[i])); for(int i=1;i<s1;i++)mx2=max(mx2,area(s[s1],s[s2],s[i])); ans=max(ans,mx1+mx2); } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lf%lf",&s[i].x,&s[i].y); if(s[i].y<s[rt].y||(s[i].y==s[rt].y&&s[i].x<s[rt].x)) rt=i; }swap(s[rt],s[1]);rt=1; sort(s+2,s+n+1,cmp); q[++top]=1;q[++top]=2; for(int i=3;i<=n;++i) { while(top>=2&&cross(s[q[top-1]],s[q[top]],s[i])<=0) --top; q[++top]=i; } for(int i=1;i<=top;i++)s[i]=s[q[i]];s[(n=top)+1]=s[1]; for(int i=1,j=2;i<=n;calc(i,j),i++) while(area(s[i],s[j],s[i+1])<area(s[i],s[j+1],s[i+1])) {++j;if(j>n)j=1;} printf("%0.3lf",ans); return 0; }
update:卡时间卡空间版,用二分求最远点 复杂度nlogn 卡到排行榜RANK 2啦
#include<cstdio> double ans=0; int n,rt=1,top=0; short*q; struct P{double x,y;}*s; double cross(P x,P y,P z) { double x0=y.x-x.x,xx=z.x-x.x,y0=y.y-x.y,yy=z.y-x.y; return x0*yy-xx*y0; } double fabs(double x){return x<0?-x:x;} double area(P x,P y,P z){return fabs(cross(x,y,z))/2.00000;} bool cmp(P x,P y){return cross(s[rt],x,y)>0;} double max(double x,double y){return x<y?y:x;} void swap(int x,int y){int t=x;x=y;y=t;} void swap(P x,P y){P t=x;x=y;y=t;} void quickSort(P*arr, int left, int right){ int i = left, j = right; P mid = arr[(i+j)/2]; while(i <= j){ while(cmp(arr[i],mid)) i ++; while(cmp(mid,arr[j])) j --; if(i <= j){ P tmp; tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; i ++; j --; } } if(i < right) quickSort(arr,i, right); if(left < j) quickSort(arr,left, j); } double solve(int l,int r,int s1,int s2) { double c,c1,c2,mx=0;int mid,ll=l,rr=r; while(l<=r) { mid=(l+r)>>1;c=area(s[s1],s[s2],s[mid]);mx=max(mx,c); if(mid==ll)r=mid-1; else if(mid==rr) l=mid+1; else { c1=area(s[s1],s[s2],s[mid-1]); c2=area(s[s1],s[s2],s[mid+1]); if(c1<c2) l=mid+1;else r=mid-1; } } return mx; } void calc(int s1,int s2) { double mx1=0,mx2=0;if(s1>s2)swap(s1,s2); /* for(int i=s1+1;i<s2;i++)mx1=max(mx1,area(s[s1],s[s2],s[i])); for(int i=s2+1;i<=n;i++)mx2=max(mx2,area(s[s1],s[s2],s[i])); for(int i=1;i<s1;i++)mx2=max(mx2,area(s[s1],s[s2],s[i])); */ mx1=max(mx1,solve(s1+1,s2-1,s1,s2)); mx2=max(mx2,max(solve(1,s1-1,s1,s2),solve(s2+1,n,s1,s2))); ans=max(ans,mx1+mx2); } int main() { scanf("%d",&n);q=new short[n+1];s=new P[n+1]; for(int i=1;i<=n;i++) { scanf("%lf%lf",&s[i].x,&s[i].y); if(s[i].y<s[rt].y||(s[i].y==s[rt].y&&s[i].x<s[rt].x)) rt=i; }swap(s[rt],s[1]);rt=1; quickSort(s,2,n); q[++top]=1;q[++top]=2; for(int i=3;i<=n;++i) { while(top>=2&&cross(s[q[top-1]],s[q[top]],s[i])<=0) --top; q[++top]=i; } for(int i=1;i<=top;i++)s[i]=s[q[i]];s[(n=top)+1]=s[1]; for(int i=1,j=2;i<=n;calc(i,j),i++) while(area(s[i],s[j],s[i+1])<area(s[i],s[j+1],s[i+1])) {++j;if(j>n)j=1;} printf("%0.3lf",ans); return 0; }
RANK1是假的吧????
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream