石油大----Contest2003 - 2020年秋季组队训练赛第七场--Problem L、Largest Quadrilateral (平面找四点组成面积最大的四边形,旋转卡壳)

题面:

在这里插入图片描述

题意:
平面上给定 n n n 个点,这 n n n 个点中选四个点组成一个四边形,问这个四边形的面积最大是多少。

题解:
很明显,最优解的四个点一定都在凸包上。

先求解凸包。

若凸包上面的点 ≤ 2 \le2 2 ,那么说明这些点共线或者重合。面积为 0 0 0

若凸包上面的点 = 3 =3 =3,则四边形的三个顶点为这三个点,剩余的那一个点选自凸包内部。枚举即可。

若凸包上面的点 > = 4 >=4 >=4,我们枚举凸包上面的任意两点,在这两点连线的两侧分别求解一个面积最大的三角形,两个三角形相加即为在当前两点确定的情况下面积最大的四边形。

但这样求解的时间复杂度是 O ( n 3 ) O(n^3) O(n3),并不能通过此题。

考虑对于一个固定的点 i i i,点 j j j 在凸包上枚举的过程中,两侧最大三角形的顶点与 j j j 有相同的单调性。即旋转卡壳可以优化到 O ( n 2 ) O(n^2) O(n2)

代码:

#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","inline","-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<bitset>
#include<map>
#include<ctime>
#include<unordered_map>
#include<set>
#include<unordered_set>
namespace onlyzhao
{
    #define ui unsigned int
    #define ll long long
    #define llu unsigned ll
    #define ld long double
    #define pr make_pair
    #define pb push_back
    #define lc (cnt<<1)
    #define rc (cnt<<1|1)
    //#define len(x)  (t[(x)].r-t[(x)].l+1)
    #define tmid ((l+r)>>1)
    #define fhead(x) for(int i=head[(x)];i;i=nt[i])
    //#define max(x,y) ((x)>(y)?(x):(y))
    //#define min(x,y) ((x)>(y)?(y):(x))
    #define one(n) for(int i=1;i<=(n);i++)
    #define rone(n) for(int i=(n);i>=1;i--)
    #define fone(i,x,n) for(int i=(x);i<=(n);i++)
    #define frone(i,n,x) for(int i=(n);i>=(x);i--)
    #define fonk(i,x,n,k) for(int i=(x);i<=(n);i+=(k))
    #define fronk(i,n,x,k) for(int i=(n);i>=(x);i-=(k))
    #define two(n,m) for(int i=1;i<=(n);i++) for(int j=1;j<=(m);j++)
    #define ftwo(i,n,j,m) for(int i=1;i<=(n);i++) for(int j=1;j<=(m);j++)
    #define fvc(vc) for(int i=0;i<vc.size();i++)
    #define frvc(vc) for(int i=vc.size()-1;i>=0;i--)
    #define forvc(i,vc) for(int i=0;i<vc.size();i++)
    #define forrvc(i,vc) for(int i=vc.size()-1;i>=0;i--)
    #define cls(a) memset(a,0,sizeof(a))
    #define cls1(a) memset(a,-1,sizeof(a))
    #define clsmax(a) memset(a,0x3f,sizeof(a))
    #define clsmin(a) memset(a,0x80,sizeof(a))
    #define cln(a,num) memset(a,0,sizeof(a[0])*num)
    #define cln1(a,num) memset(a,-1,sizeof(a[0])*num)
    #define clnmax(a,num) memset(a,0x3f,sizeof(a[0])*num)
    #define clnmin(a,num) memset(a,0x80,sizeof(a[0])*num)
    #define sc(x) scanf("%d",&x)
    #define sc2(x,y) scanf("%d%d",&x,&y)
    #define sc3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define scl(x) scanf("%lld",&x)
    #define scl2(x,y) scanf("%lld%lld",&x,&y)
    #define scl3(x,y,z) scanf("%lld%lld%lld",&x,&y,&z)
    #define scf(x) scanf("%lf",&x)
    #define scf2(x,y) scanf("%lf%lf",&x,&y)
    #define scf3(x,y,z) scanf("%lf%lf%lf",&x,&y,&z)
    #define scs(x) scanf("%s",x+1)
    #define scs0(x) scanf("%s",x)
    #define scline(x) scanf("%[^\n]%*c",x+1)
    #define scline0(x) scanf("%[^\n]%*c",x)
    #define pcc(x) putchar(x)
    #define pc(x) printf("%d\n",x)
    #define pc2(x,y) printf("%d %d\n",x,y)
    #define pc3(x,y,z) printf("%d %d %d\n",x,y,z)
    #define pck(x) printf("%d ",x)
    #define pcl(x) printf("%lld\n",x)
    #define pcl2(x,y) printf("%lld %lld\n",x,y)
    #define pcl3(x,y,z) printf("%lld %lld %d\n",x,y,z)
    #define pclk(x) printf("%lld ",x)
    #define pcf2(x) printf("%.2f\n",x)
    #define pcf6(x) printf("%.6f\n",x)
    #define pcf8(x) printf("%.8f\n",x)
    #define pcs(x) printf("%s\n",x+1)
    #define pcs0(x) printf("%s\n",x)
    #define pcline(x) printf("%d**********\n",x)
    #define casett int tt;sc(tt);int pp=0;while(tt--)

    char buffer[100001],*S,*T;
    inline char Get_Char()
    {
        if (S==T)
        {
            T=(S=buffer)+fread(buffer,1,100001,stdin);
            if (S==T) return EOF;
        }
        return *S++;
    }
    inline ll read()
    {
        char c;ll re=0;
        for(c=Get_Char();c<'0'||c>'9';c=Get_Char());
        while(c>='0'&&c<='9') re=re*10+(c-'0'),c=Get_Char();
        return re;
    }
};
using namespace onlyzhao;
using namespace std;

#define double ll
#define int ll
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e18;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1.0);
const int hp=13331;
const int maxn=110;
const int maxm=100100;
const int up=100000;
const int maxp=5010;

int sgn(double x)
{
    if(x==0) return 0;
    else if(x<0) return -1;
    else  return 1;
}


struct Point
{
    double  x,y;
    Point(){}
    Point(double xx,double yy)
    {
        x=xx,y=yy;
    }

    void input(void)
    {
        scanf("%lld%lld",&x,&y);
    }
    bool operator == (const Point &b) const
    {
        return sgn(x-b.x)==0&&sgn(y-b.y)==0;
    }

    bool operator < (const Point &b) const
    {
        if(sgn(x-b.x)!=0) return x<b.x;
        else return sgn(y-b.y)<0;
    }

    Point operator + (const Point &b) const
    {
        return Point(x+b.x,y+b.y);
    }

    Point operator - (const Point &b) const
    {
        return Point(x-b.x,y-b.y);
    }

    Point operator * (const double &k) const
    {
        return Point(x*k,y*k);
    }

    Point operator / (const double &k) const
    {
        return Point(x/k,y/k);
    }

    double operator ^ (const Point &b) const
    {
        return x*b.y-y*b.x;
    }
    double dis(const Point &b) const
    {
        return (x-b.x)*(x-b.x)+(y-b.y)*(y-b.y);
    }
};


struct polygon
{
    int n;
    Point p[maxp];
    void input(int nn)
    {
        n=nn;
        for(int i=0;i<n;i++)
            p[i].input();
    }

    struct cmp
    {
        Point p;
        cmp(const Point &p0) { p=p0;}
        bool operator()(const Point &aa,const Point &bb)
        {
            Point a=aa,b=bb;
            int d=sgn((a-p)^(b-p));
            if(d==0)
                return sgn(a.dis(p)-b.dis(p))<0;
            return d>0;
        }
    };

    void norm(void)
    {
        Point mi=p[0];
        for(int i=1;i<n;i++) mi=min(mi,p[i]);
        sort(p,p+n,cmp(mi));
    }
    void get_convex_graham(polygon &convex)
    {
        norm();
        int &top=convex.n;
        top=0;
        if(n==1)
        {
            top=1;
            convex.p[0]=p[0];
            return ;
        }
        if(n==2)
        {
            top=2;
            convex.p[0]=p[0];
            convex.p[1]=p[1];
            if(convex.p[0]==convex.p[1]) top--;
            return ;
        }

        convex.p[0]=p[0];
        convex.p[1]=p[1];
        top=2;
        for(int i=2;i<n;i++)
        {
            while(top>1&&sgn((convex.p[top-1]-convex.p[top-2])^(p[i]-convex.p[top-2]))<=0)
                top--;
            convex.p[top++]=p[i];
        }
        if(convex.n==2&&(convex.p[0]==convex.p[1])) convex.n--;
    }
};
double cross(Point A,Point B,Point C)
{
    return (B-A)^(C-A);
}

bool ha[maxp];

signed main(void)
{
    polygon p,q;
    int tt;
    scanf("%lld",&tt);
    while(tt--)
    {
        int n;
        scanf("%lld",&n);
        memset(ha,0,sizeof(ha));
        p.input(n);
        p.get_convex_graham(q);

        if(q.n<=2)
        {
            printf("0\n");
            continue;
        }


        for(int i=0;i<q.n;i++)
        {
            for(int j=0;j<p.n;j++)
            {
                if(q.p[i]==p.p[j])
                {
                    ha[j]=true;
                    break;
                }
            }
        }
        int now=0;
        for(int i=0;i<p.n;i++)
        {
            if(ha[i]) continue;
            p.p[now++]=p.p[i];
        }
        p.n=now;


        if(q.n==3)
        {
            ll maxx=0;
            for(int i=0;i<p.n;i++)
            {
                maxx=max(maxx,abs(cross(q.p[0],q.p[1],p.p[i]))+abs(cross(q.p[0],q.p[2],p.p[i])));
                maxx=max(maxx,abs(cross(q.p[1],q.p[0],p.p[i]))+abs(cross(q.p[1],q.p[2],p.p[i])));
                maxx=max(maxx,abs(cross(q.p[2],q.p[0],p.p[i]))+abs(cross(q.p[2],q.p[1],p.p[i])));
            }
            if(maxx%2) printf("%lld.5\n",maxx/2);
            else printf("%lld\n",maxx/2);
            continue;
        }

        ll maxx=0;
        int cnt=q.n;
        q.p[q.n]=q.p[0];
        for(int i=0;i<q.n;i++)
        {
            int k=(i+1)%cnt,h=(i+3)%cnt;
            for(int j=i+2;j<=i+cnt-2;j++)
            {
                while(abs(cross(q.p[i],q.p[j%cnt],q.p[k]))<abs(cross(q.p[i],q.p[j%cnt],q.p[k+1])))
                    k=(k+1)%cnt;
                while(abs(cross(q.p[i],q.p[j%cnt],q.p[h]))<abs(cross(q.p[i],q.p[j%cnt],q.p[h+1])))
                    h=(h+1)%cnt;
                maxx=max(maxx,abs(cross(q.p[i],q.p[j%cnt],q.p[k]))+abs(cross(q.p[i],q.p[j%cnt],q.p[h])));
            }
        }
        if(maxx%2) printf("%lld.5\n",maxx/2);
        else printf("%lld\n",maxx/2);
    }
    return 0;
}



©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页