[BZOJ2338][HNOI2011]数矩形(计算几何)

题目描述

传送门

题目大意:给出二维平面上的n个点,求一个最大的矩形,它的顶点都在给出的点上。

题解

首先预处理出所有的线段,中点相同、长度相同的两条线段可以组成一个合法的矩形
将所有的线段按照一维中点、一维长度、一维斜率排序,对于中点相同、长度相同的线段必定在一段区间里,并且对于一条线段,取到最大值的另一条线段单峰,用两个指针扫一下就行了

代码

#include
#include
#include
#include
#include
using namespace std;
#define db double
#define LL long long
#define N 1505

const LL inf=1e18;
int n,cnt;
LL ans,x[N],y[N];
struct Seg
{
    int id,jd;
    LL x,y,len;
    double k;
}s[N*N];

LL qr(LL x){return x*x;}
int cmp(Seg a,Seg b)
{
    return a.xx||(a.x==b.x&&a.yy)||(a.x==b.x&&a.y==b.y&&a.lenx==b.x&&a.y==b.y&&a.len==b.len&&a.kx){return (x>0)?x:-x;}
LL Area(Seg a,Seg b)
{
    LL vx=x[b.id]-x[a.id],vy=y[b.id]-y[a.id];
    LL wx=x[b.jd]-x[a.id],wy=y[b.jd]-y[a.id];
    return Abs(vx*wy-vy*wx);
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;++i) scanf("%lld%lld",&x[i],&y[i]);
    for (int i=1;i<=n;++i)
        for (int j=i+1;j<=n;++j)
        {
            ++cnt;
            s[cnt].id=i,s[cnt].jd=j;
            s[cnt].x=x[i]+x[j],s[cnt].y=y[i]+y[j];
            s[cnt].len=qr(x[i]-x[j])+qr(y[i]-y[j]);
            if (x[i]==x[j]) s[cnt].k=inf;
            else s[cnt].k=((db)y[i]-(db)y[j])/((db)x[i]-(db)x[j]);
        }
    sort(s+1,s+cnt+1,cmp);
    for (int i=1,j;i<=cnt;i=j+1)
    {
        j=i;
        while (s[j].x==s[i].x&&s[j].y==s[i].y&&s[j].len==s[i].len)
            ++j;
        --j;
        int l=i,r=i;
        while (l<=j)
        {
            r=max(r,l);
            while (rs[l],s[r])<=Area(s[l],s[r+1]))
                ++r;
            ans=max(ans,Area(s[l],s[r]));
            ++l;
        }
    }
    printf("%lld\n",ans);
}

你可能感兴趣的:(题解,省选,计算几何)