通过这题才知道有三分法,我们知道二分法对于单调函数而言是个非常好的方法,同样,对于凸性函数则用三分法的效率还是很高的。
三分法:http://www.cppblog.com/abilitytao/archive/2010/11/07/132863.html
坐标旋转:x1=cos(angle)*x-sin(angle)*y;
y1=sin(angle)*x+cos(angle)*y;
题意:求覆盖所有点的最小正方形面积
思路:每次进行坐标旋转,求出旋转后的坐标最大差值作为正方形的边,用三分法求边最小时的旋转角。
代码如下:
#include<stdio.h>
#include<math.h>
#include<iostream>
#include<algorithm>
#define pi acos(-1.0)
#define F(i,n) for(int i=0;i<n;i++)
#define eps 1e-8
#define maxn 35
#define Max(a,b) a>b?a:b
#define Min(a,b) a<b?a:b
#define sqr(x) ((x)*(x))
#define INF 0x3f3f3f3f
using namespace std;
struct cpoint
{
double x,y;
};
cpoint cp[maxn];
int n,ca;
double cal(double angle)
{
double xmax,xmin,ymax,ymin,y,x;
xmax=ymax=-INF;
xmin=ymin=INF;
F(i,n)
{
x=cos(angle)*cp[i].x-sin(angle)*cp[i].y;
y=sin(angle)*cp[i].x+cos(angle)*cp[i].y;
xmax=Max(xmax,x);
xmin=Min(xmin,x);
ymax=Max(ymax,y);
ymin=Min(ymin,y);
}
double L=Max(xmax-xmin,ymax-ymin);
return L;
}
void solve()
{
double low=0,hight=0.5*pi,mid,midmid;
while(fabs(hight-low)>eps)
{
mid=(hight+low)/2;
midmid=(mid+hight)/2;
if(cal(mid)<=cal(midmid))
hight=midmid;
else low=mid;
}
printf("%.2lf\n",sqr(cal(mid)));
}
int main()
{
scanf("%d",&ca);
while(ca--)
{
scanf("%d",&n);
F(i,n)
{
scanf("%lf %lf",&cp[i].x,&cp[i].y);
}
solve();
}
return 0;
}