引用大牛博客内容- -#,勿喷
题目大意:
给定二维平面的n个点,要求一个面积最小的正方形,使其能覆盖所有的点。
解题思路:
旋转坐标系,三分法。
如果正方形两相邻边是与坐标轴平行的,那么只需求出所有点的横坐标差的最大值,纵坐标差的最大值,然后再求两者的最大值,同样的道理当正方形相邻两边与坐标轴不平行时,旋转坐标轴,使新的坐标轴平行正方形的两相邻边,然后把旧坐标轴上的点的坐标全部转化到新的坐标轴上,再求出横纵坐标差的最大值,取两者的最大值即可。分析知二维空间上,对于任意正方形的位置,总能顺时针旋转坐标轴0~90‘ 达到满足要求。
如图所示当坐标旋转a角度时可以求出 x1=x*cos(a)-y*sin(a); y1=x*sin(a)+y]*cos(a); 可以证明它们都是凸性函数,故他们差的最大值也是凸性函数,故可以用三分法,对旋转角度进行三分,求出最小的满足要求的正方形,详细过程见代码。
注意:用c++交,g++会出问题;
#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;
struct sa
{
double x,y;
}p[35];
int n;
const double pi=acos(-1.0);
const double eps=1e-6;
double area(double a)
{
return a*a;
}
double cal(double z)
{
double x,y;
double maxx=-1000000,minx=10000000,maxy=-10000000,miny=10000000;
for(int i=0;i<n;i++)
{
x=p[i].x*cos(z)-p[i].y*sin(z);
y=p[i].x*sin(z)+p[i].y*cos(z);
if(minx>x) minx=x;
if(miny>y) miny=y;
if(maxx<x) maxx=x;
if(maxy<y) maxy=y;
}
return max(area(maxx-minx),area(maxy-miny));
}
double div()
{
double left=0,right=pi/2.0;
double ans1,ans2;
double m,mm;
do
{
m=(left+right)/2.0;
mm=(right+m)/2.0;
ans1=cal(m);
ans2=cal(mm);
if(ans1<ans2)
right=mm;
else
left=m;
}while(fabs(ans1-ans2)>eps);
return ans1;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%lf%lf",&p[i].x,&p[i].y);
}
printf("%.2lf\n",div());
}
return 0;
}