After a day trip with his friend Dick, Harry noticed a strange pattern of tiny holes in the door of his SUV. The local American Tire store sells fiberglass patching material only in square sheets. What is the smallest patch that Harry needs to fix his door?
Assume that the holes are points on the integer lattice in the plane. Your job is to find the area of the smallest square that will cover all the holes.
The first line of input contains a single integer T expressed in decimal with no leading zeroes, denoting the number of test cases to follow. The subsequent lines of input describe the test cases.
Each test case begins with a single line, containing a single integer n expressed in decimal with no leading zeroes, the number of points to follow; each of the following n lines contains two integers x and y, both expressed in decimal with no leading zeroes, giving the coordinates of one of your points.
You are guaranteed that T ≤ 30 and that no data set contains more than 30 points. All points in each data set will be no more than 500 units away from (0,0).
Print, on a single line with two decimal places of precision, the area of the smallest square containing all of your points.
2 4 -1 -1 1 -1 1 1 -1 1 4 10 1 10 -1 -10 1 -10 -1
4.00 242.00
题意:寻找可以覆盖平面上n个点的最小正方形的面积
做这题的时候想起了car的旅行路线的有趣的矩形……然后试了试样例,正方形果然是这样的:
好吧,你又一次伤害了我的心灵。不说什么,我们来想想怎么办吧!我们知道,如果正方形的边与坐标系平行,那么这个问题就非常简单了,只需要统计最高的x,最低的x,最高的y,最低的y,然后选择高低x、y的差值的更大者作为边长,答案就出来了。
我们往这方面想,可以发现,我们其实可以旋转坐标系,然后计算出旋转后的每一个点的新坐标,就可以很快的求出正方形的边长了。而根据玄学与直觉,正方形的边长与坐标系的旋转角度的关系一定是一个单峰值函数,而旋转坐标系其实无异于逆向旋转每一个点,那么我们根据点选转的公式((x,y)是原来的点,(x0,y0)是旋转后的点,(rx0,ry0)是沿着旋转的点):
x0=(x-rx0)*cos(A)-(y-ry0)*sin(A)+rx0
y0=(x-rx0)*sin(A)+(y-ry0)*cos(A)+ry0
将(rx0,ry0)=(0,0)带入后,就得到
x0=(x)*cosA-y*sin(A)
y0=(x)*sinA+y*cos(A)
再根据是单峰函数用三分法就可以求解了!
不过,我倒没有用三分,而是用了一个非常鬼畜的方法……就是先二分中间点mid,再建立一个变量为mid-(1e-n)(n一般为5~6),看f(mid)和f(mid-(1e-n))谁大一些,mid大的话说明是在上升的一侧,否则是在下降的一侧,然后向峰值进行调整,直到l、r相差小于eps为止。其实后来发现和三分法有异曲同工之妙,只是三分两端点之间间隔了三分之一段,而这种方法却只间隔了1e-n,不过这样会有精度误差的——还是用三分好些……
代码我懒得改成三分了,所以虽然标题是三分,但还是不要将三分理解成我的代码QWQ(话说往左移了那么1e-n所以精度误差有些大必须调成1e-8才可以,eps相应的就变成了1e-10有些慢啊)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define mypi 3.1415926535897932
#define cg(a) a/180.0*mypi
#define eps 1e-10
#define lef(a) a-(1e-8)
#define inf 1e+20
#define sqr(a) ((a)*(a))
int t,n;
struct Point{double x,y;}P[50];
bool equal(double a,double b){return a-b<eps&&b-a<eps;}
double ans(double a)
{
double xmax=-inf,xmin=inf,ymax=-inf,ymin=inf;
for(int i=1;i<=n;i++)
{
double x0=P[i].x*cos(a)-P[i].y*sin(a);
double y0=P[i].x*sin(a)+P[i].y*cos(a);
xmax=max(xmax,x0);
xmin=min(xmin,x0);
ymax=max(ymax,y0);
ymin=min(ymin,y0);
}
return sqr(max(xmax-xmin,ymax-ymin));
}
int main()
{
scanf("%d",&t);
for(;t--;)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lf%lf",&P[i].x,&P[i].y);
double l=0,r=mypi;
while(!equal(l,r))
{
double mid=(l+r)/2;
double s1=ans(mid),s2=ans(lef(mid));
if(s1<s2)
l=mid;
else
r=mid;
}
double cnt=ans(l);
printf("%.2lf\n",cnt);
}
}