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

211 篇文章 0 订阅
55 篇文章 0 订阅

题目描述

传送门

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

题解

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

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
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.x<b.x||(a.x==b.x&&a.y<b.y)||(a.x==b.x&&a.y==b.y&&a.len<b.len)||(a.x==b.x&&a.y==b.y&&a.len==b.len&&a.k<b.k);
}
LL Abs(LL x){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 (r<j&&Area(s[l],s[r])<=Area(s[l],s[r+1]))
                ++r;
            ans=max(ans,Area(s[l],s[r]));
            ++l;
        }
    }
    printf("%lld\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值