HNOI 2011 数矩形
题目连接:今天BZOJ的速度实在不敢恭维,自己上OJ找吧。
题意:给定n个点,求能够组成矩形的最大面积。
题目分析:最直观的算法就是枚举每三个点组成的矩形,然后二分判断剩下的点上有没有点。时间复杂度为O(n3),四十分大概。
还有一种更好的算法,首先要了解矩形的基本性质,对角线长度相等(不相等那是平行四边形)且相互平分(重点)。有了它一切都好说了。先在O(n2)的时间算出每两个点连接线段的长度和中点坐标求出来,然后根据中点坐标排序,判断每对中点相同的边能否构成矩形,更新答案即可。虽然最坏复杂度可能达到O(n3),但是数据好像没给这么变态...所以猥琐的过了...
其实只有中点坐标和线段长度需要double,别的直接int就行了,去掉一些强制转换可能会快点。不过鉴于本人比较懒...所以没改。
下面给出代码
View Code
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
#define MaxN 1510
struct point
{
double x,y;
};
struct atp
{
point a,b,avr;
double size;
}a[MaxN*MaxN/2];
int n,tot=0;
double ans=0;
int X[MaxN],Y[MaxN];
inline void add(int i,int j,point z)
{
tot++;
a[tot].a.x=(double)X[i];
a[tot].a.y=(double)Y[i];
a[tot].b.x=(double)X[j];
a[tot].b.y=(double)Y[j];
a[tot].size=(double) sqrt(abs((X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j])));
a[tot].avr=z;
}
inline point check(int i,int j)
{
point t;
t.x=(double)(X[i]+X[j])/2;
t.y=(double)(Y[i]+Y[j])/2;
return t;
}
double get(point x,point y)
{
return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));
}
void init()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d%d",&X[i],&Y[i]);
for (int i=1;i<n;i++)
for (int j=i+1;j<=n;j++)
if (X[i]!=X[j] || Y[i]!=Y[j])
add(i,j,check(i,j));
}
bool cmp(atp x,atp y)
{
if (x.avr.x<y.avr.x) return true; else
if (x.avr.x>y.avr.x) return false; else
if (x.avr.y<y.avr.y) return true; else return false;
}
void work()
{
for (int i=1;i<tot;i++)
for (int j=i+1;a[j].avr.x==a[i].avr.x && a[i].avr.y==a[j].avr.y;j++)
{
if (a[i].avr.x==a[j].avr.x && a[i].avr.y==a[j].avr.y && a[i].size==a[j].size)
{
ans=max(ans,(double)abs(get(a[i].a,a[j].a))*abs(get(a[i].a,a[j].b)));}
}
}
int main()
{
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
init();
sort(a+1,a+tot+1,cmp);
work();
printf("%.0lf",ans);
return 0;
}