给出平面上一些点(坐标),让我们在平面上选择一个正方形能够覆盖这些所有的点,求这个正方形的最小面积。
我们很容易找到一个符合要求的正方形,也就是所有边都平行于坐标轴的正方形,那么我们就只找平行于坐标轴的正方形,我们将每个点都旋转一定的角度,他们的相对位置不变,而正方形却相对于点在旋转,面积在改变,那么就可以找到最小的正方形.
我们只需要考虑最优的旋转角度.
假设旋转的角度为f,初始点的坐标为(x,y)与x轴的夹角为a,距离坐标原点的长度为len,那么x = cos(a)*len,y = sin(a)*len,nx = cos(a+f)*len,ny = sin(a+f)*len
拆开nx = cos(a)*cos(f)*len-sin(a)*sin(f)*len,ny = sin(a)*cos(f)*len+cos(a)*sin(f)*len
也就是说 nx = cos(f)*x-sin(f)*y,ny = sin(f)*x+cos(f)*y;
正方形的边长等于max(rightx-leftx,upy-downy) = max(cos(f)*(x1-x2)-sin(f)*(y1-y2),sin(f)*(x1-x2)+cos(f)*(y1-y2))(x1>x2 && y1>y2)
等于 max(sqrt((x1-x2)^2+(y1-y2)^2)sin(f+p1),sqrt((x1-x2)^2+(y1-y2)^2)sin(f+p2))
那么边长是由K*sin(f+p)转化而来的,那么在这个函数上一定存在一个角度使得边长最小,还有一个很显然的就是旋转角度在180°之内根据对称一定会找到最优解,那么f+p就在(-0.5*pi,pi)之间那么就是一个单峰函数,那么就可以三分角度了。
不知道为什么交G++就WA了,交C++就A了。。。
#include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <cstring> using namespace std; const double pi = acos(-1.0); const double eps = 1e-8; const int maxn = 510; const double inf = 0xfffffff; struct node{ double x,y; }p[maxn]; int n,T; node rotate(node p,double k){ node a; a.x = p.x*cos(k)-p.y*sin(k); a.y = p.x*sin(k)+p.y*cos(k); return a; } double calc(double k){ double minx = inf,miny = inf; double maxx = -inf,maxy = -inf; for(int i = 1;i <= n;++i){ node np; np = rotate(p[i],k); minx = min(minx,np.x),miny = min(miny,np.y); maxx = max(maxx,np.x),maxy = max(maxy,np.y); } return max(maxx-minx,maxy-miny); } int main(){ scanf("%d",&T); while(T--){ scanf("%d",&n); memset(p,0,sizeof(p)); for(int i = 1;i <= n;++i){ scanf("%lf%lf",&p[i].x,&p[i].y); } double l = 0.0,r = pi,mid,rmid; while (l + eps < r) { mid = (l+r)/2; rmid = (mid+r)/2; if(calc(mid) < calc(rmid)) r = rmid; else l = mid; } double len = calc(l); printf("%.2lf\n",len*len); } return 0; }