P4166 [SCOI2007]最大土地面积

传送门

首先,四边形的四个点肯定都在凸包上(别问我为什么我也不知道,感性理解一下好了)

那么我们可以求出凸包之后\(O(n^4)\)暴力枚举,据说在随机数据下凸包上的点只有\(O(logn)\)个可过

然而出题人大大的没有良心,上面那样写只有50分

我们考虑枚举对角线,那么剩下的两个点就是在这条对角线两边,也就是说要分别找到和这条边面积最大的点。发现这个可以用旋转卡壳来优化,计算面积用叉积,于是总的时间复杂度即为\(O(n^2)\)

//minamoto
#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
using namespace std;
//template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
const int N=10005;
struct node{double x,y;}p[N],st[N];
int n,k,top;double ans;
inline bool cmp(node a,node b){
    double A=atan2(a.y-p[1].y,a.x-p[1].x);
    double B=atan2(b.y-p[1].y,b.x-p[1].x);
    return A!=B?A<B:a.x<b.x;
}
inline double cross(node a,node b,node c){return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);}
int main(){
//	freopen("testdata.in","r",stdin);
    scanf("%d",&n),k=1;
    fp(i,1,n){
        scanf("%lf%lf",&p[i].x,&p[i].y);
        if(p[i].y<p[k].y||(p[i].y==p[k].y&&p[i].x<p[k].x))k=i;
    }swap(p[1],p[k]),sort(p+2,p+1+n,cmp);
    st[0]=p[1],st[1]=p[2],top=1;
    fp(i,3,n){
        while(top&&cross(st[top-1],p[i],st[top])>=0)--top;
        st[++top]=p[i];
    }
    st[++top]=p[0];
    if(top==4)return printf("%.3lf\n",(cross(st[0],st[1],st[2])+cross(st[2],st[3],st[0]))/2);
    fp(i,0,top)for(register int j=i+2,k=i+1,l=(i+3)%top;j<top;++j){
        while(cross(st[i],st[k],st[j])<cross(st[i],st[k+1],st[j]))k=(k+1)%top;
        while(cross(st[j],st[l],st[i])<cross(st[j],st[l+1],st[i]))l=(l+1)%top;
        ans=max(ans,cross(st[i],st[k],st[j])+cross(st[j],st[l],st[i]));
    }printf("%.3lf\n",ans/2);return 0;
}
posted @ 2018-11-22 14:49  bztMinamoto  阅读(118)  评论(0编辑  收藏  举报
Live2D