题目大意:给出N个点,求出能够涵盖全部点的最小正方形的面积。
思 路:1> 有一个很重要的公式,能够求出一个点在不同的坐标轴下对应的点
x(转化后)=x*cos(a) -y*sin(a)
y(转化后)=y*cos(a)+x*sin(a) 其中a 是坐标转移的角度
利用这个可以求出转移后该点的位置,可以找到转移后max(x) min(x)
和 max(y) min(y) 由此可以再max(x)-min(x) 和max(y)-min(y) 中找到那
个最大的边作为正方形的边
2>如果按正常思路穷举的话,肯定会超时。在这种穷举会超时的情况下使用
二分法和三分法,这里只能使用三分法。
二分与三分的区别:
二分法适用于单调函数中逼近求解某个点的值
三分法适用于求解凸函数中逼近求解某点的值
三分法解释:
如图,这个凸函数要求的是定点为正解
mid=(left+right)/2; mmid=(mid+right)/2;
判断函数fun() 根据题目编辑
1: 当 fun(mid)<fun(mmid) 可以知道 mid在顶点的左侧,将左边的范围缩小
left=mid
2: 当fun(mid)>fun(mmid) 可以知道mmid点在顶点的右侧,右边的范围可
以缩小 right=mmid
3> 此题在不断旋转角度的过程中面积也在变化,而变化规律呈现凸型,因此
使用三分的方法更适合。
代码如下:
#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <math.h>
#include <vector>
#include <string>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m;
double x[40],y[40];
const double maxn=0xfffffffffffff;//最大值
const double minn=-0xfffffffffffff;//最小值
const double PI=acos(-1.0);//cos(180)=-1 acos表示值为-1的弧度 即180
double work(double a)
{
double maxx=minn,minx=maxn,maxy=minn,miny=maxn;
int i;
for(i=1;i<=n;i++)
{
double tx=x[i]*cos(a)-y[i]*sin(a); //计算转移后的x坐标
double ty=y[i]*cos(a)+x[i]*sin(a); //计算转移后的y坐标
maxx=max(maxx,tx); //边长为
minx=min(minx,tx); //各个极值点
maxy=max(maxy,ty); //的
miny=min(miny,ty); //对应坐标差
}
return max(maxx-minx,maxy-miny);//最大差作为边长
}
int main()
{
int i;
cin>>m;
while(m--)
{
cin>>n;
for(i=1;i<=n;i++)
scanf("%lf%lf",&x[i],&y[i]);
double ll,rr,mid,midmid;
ll=0;
rr=PI;
while(ll+0.0000000000001<rr) // 注意精度
{
//三分
mid=(ll+rr)/2.0;
midmid=(mid+rr)/2.0;
if(work(mid)<=work(midmid))
rr=midmid;
else
ll=mid;
}
double temp=work(ll)*work(ll);
printf("%.2lf\n",temp);
}
return 0;
}