poj 3301 Texas Trip(旋转+三分)

题目:http://poj.org/problem?id=3301

大意:给出一些点求出最小的正方形面积把它们都覆盖掉。

要解决它我们需要会一些基础知识:坐标旋转公式,三分搜索算法。
poj 3301 Texas Trip(旋转+三分)_第1张图片

逆时针旋转:x=xcosθ+ysinθ;  y=ycosθ-xsinθ
顺时针旋转:x=xcosθ-ysinθ;  y=ycosθ+xsinθ
分析可知,在一个π内可以找到最佳的边长,构造出能够覆盖所有的点同时也是最小的正方形。这涉及到极值问题,所以自然联想到三分搜索算法。
以例子2作为说明对象:
poj 3301 Texas Trip(旋转+三分)_第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。

你可能感兴趣的:(数学,poj,三分搜索)