Problem: Texas Trip
Description: 给你一些点的集合,让你用一个最小的正方形来覆盖所有的点,求这个正方形的面积。
Solution: 三分求极值+图形旋转。我们知道,求最小正方形也就是求最小边长,如果这个正方形是平行于X轴的,那么最小边长就是任意两个点横向和纵向的最大值。那么我们要绕原点旋转这些点,这个其实也可以看成是正方形绕这些点旋转。那么我们对于旋转了rad度的这些点。求得横向坐标和纵向坐标的最大值也就是当前的正方形边长。坐标变换公式:
X=x∗sin(rad)−y∗cos(rad)
Y=x∗cos(rad)+y∗sin(rad)
可以观察到这是一个凹函数,那么对于这种函数我们可以用三分来求得极值。这是必须的。
对于这个题。我们求最小值。那么就是当mid比mmid更靠近也就是cal(mid) < cal(mmid)时r=mmid。不懂的可以百度三分算法。
Code(C++):
#include <stdio.h>
#include <string.h>
#include <math.h>
#define MIN(a,b) ((a)>(b)? (b):(a))
#define MAX(a,b) ((a)<(b)? (b):(a))
const int M=35;
const double PI=4*atan(1.0);
const double EPS=1e-10;
typedef struct tagPoint{
int x,y;
}Point;
int n;
Point points[M];
double cal(double rad)
{
double ans=0;
double SIN=sin(rad);
double COS=cos(rad);
for(int i=0;i<n-1;i++)
for(int j=i+1;j<n;j++){
double tmp1=fabs((points[i].x-points[j].x+0.0)*COS-(points[i].y-points[j].y+0.0)*SIN);
double tmp2=fabs((points[i].x-points[j].x+0.0)*SIN+(points[i].y-points[j].y+0.0)*COS);
ans=MAX(ans,MAX(tmp1,tmp2));
}
return ans;
}
double deal()
{
double l=0,r=PI,mid,mmid;
while(fabs(r-l)>EPS){
mid=(r+l)/2;
mmid=(mid+r)/2;
//fabs(cal(mid)-cal(mmid))<EPS? r=mmid:l=mid;
cal(mid)<cal(mmid)? r=mmid:l=mid;
}
return cal(l)*cal(l);
}
int main()
{
int N;
for(scanf("%d",&N);N--;){
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d%d",&points[i].x,&points[i].y);
double ans=deal();
printf("%.2f\n",ans);
}
return 0;
}