题目链接:
http://poj.org/problem?id=3301
题目大意:
给定二维平面的n个点,要求一个面积最小的正方形,使其能覆盖所有的点。
解题思路:
旋转坐标系,三分法。
如果正方形两相邻边是与坐标轴平行的,那么只需求出所有点的横坐标差的最大值,纵坐标差的最大值,然后再求两者的最大值,同样的道理当正方形相邻两边与坐标轴不平行时,旋转坐标轴,使新的坐标轴平行正方形的两相邻边,然后把旧坐标轴上的点的坐标全部转化到新的坐标轴上,再求出横纵坐标差的最大值,取两者的最大值即可。分析知二维空间上,对于任意正方形的位置,总能顺时针旋转坐标轴0~90‘ 达到满足要求。
如图所示当坐标旋转a角度时可以求出 x1=x*cos(a)-y*sin(a); y1=x*sin(a)+y]*cos(a); 可以证明它们都是凸性函数,故他们差的最大值也是凸性函数,故可以用三分法,对旋转角度进行三分,求出最小的满足要求的正方形,详细过程见代码。
#include<iostream> //g++不能过 c++可以过,精度处理方式不同
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#define eps 1e-12
#define INF (1<<25)
#define PI acos(-1.0)
using namespace std;
double ppx[40],ppy[40];
int n;
double Cal(double a)
{
double xMin=INF*1.0,yMin=INF*1.0,xMax=-INF*1.0,yMax=-INF*1.0;
for(int i=1;i<=n;i++)
{
double x1=ppx[i]*cos(a)-ppy[i]*sin(a);
double y1=ppx[i]*sin(a)+ppy[i]*cos(a);
if(x1>xMax)
xMax=x1;
if(x1<xMin)
xMin=x1;
if(y1>yMax)
yMax=y1;
if(y1<yMin)
yMin=y1;
}
if(xMax-xMin<yMax-yMin)
return yMax-yMin;
else
return xMax-xMin;
}
int main()
{
int t;
int x,y;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
ppx[i]=x+500.0;
ppy[i]=y+500.0;
}
double le=0,ri=PI,mid,mmid;
double mid_va,mmid_va;
while(le+eps<=ri)
{
mid=(le+ri)/2;
mmid=(mid+ri)/2;
mid_va=Cal(mid);
mmid_va=Cal(mmid);
if(mid_va<mmid_va)
ri=mmid;
else
le=mid;
}
printf("%.2lf\n",Cal(le)*Cal(le));
}
return 0;
}