题目:http://poj.org/problem?id=3301
大意:给出一些点求出最小的正方形面积把它们都覆盖掉。
要解决它我们需要会一些基础知识:坐标旋转公式,三分搜索算法。
逆时针旋转:x=xcosθ+ysinθ; y=ycosθ-xsinθ
顺时针旋转:x=xcosθ-ysinθ; y=ycosθ+xsinθ
分析可知,在一个π内可以找到最佳的边长,构造出能够覆盖所有的点同时也是最小的正方形。这涉及到极值问题,所以自然联想到三分搜索算法。
以例子2作为说明对象:
不旋转时正方形的边长是20,当旋转时,可以把坐标系看作和正方形一起旋转,它们的定点是正方形的中心,也是原点。最后找到最小的边长:abs(A.x-D.x)
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; const int INF=0x3f3f3f3f,pi=3.1415926; typedef struct Point{ int x,y; }point; point p[1005]; double cal(double angle,int n){ double minx=INF,maxx=-INF,miny=INF,maxy=-INF; double tx,ty; for(int i=0;i<n;i++){ tx=p[i].x*cos(angle)-p[i].y*sin(angle); ty=p[i].y*cos(angle)+p[i].x*sin(angle); minx=min(minx,tx); maxx=max(maxx,tx); miny=min(miny,ty); maxy=max(maxy,ty); } return max(maxx-minx,maxy-miny); } int main() { //freopen("cin.txt","r",stdin); int t; cin>>t; while(t--){ int n; scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%d%d",&p[i].x,&p[i].y); } double l=0,r=pi,mid1,mid2,q1,q2; while(r-l>1e-9){ //care precision mid1=l+(r-l)/3; mid2=r-(r-l)/3; q1=cal(mid1,n),q2=cal(mid2,n); if(q1<q2)r=mid2; else l=mid1; } printf("%.2lf\n",cal(l,n)*cal(l,n)); } return 0; }注意设置的精度,过小了会WA。