POJ 3301 Texas Trip[三分]

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

题目大意

给出平面中的点集,求可以覆盖这些点的最小面积正方形。

题目分析

问题是要求最小的正方形,假设这个正方形的边都是分别与坐标轴平行,也就是说正方形没有旋转一定的角度,那么我们只要考虑最上,最下,最左,最右 的点即可,当正方形旋转过一定的角度d是我们也只要考虑最边上的点的距离差即可(故这题也可用枚举旋转角度的方法来求解,但要注意步长的选取以保证精度)。

假设旋转角度为d,那么枚举每两个点关于旋转角度为d的直线距离取最大值,即可保证覆盖所有的点,在两个方向上这样的距离分别为:

  dis1 = fabs(cos(d) * (y[i] - y[j]) - sin(d) * (x[i] - x[j]))

  dis2 = fabs(sin(d) * (y[i] - y[j]) + cos(d) * (x[i] - x[j]))

以上式子很好推导,自己画出坐标系,分析即可。

当然dis1dis2大小不一定一致,要保证图形是覆盖所有点的正方形,所以我们选取较大者为边长。

精度问题:解决这个问题可以迭代M次,每次迭代把上一次得到的最优值附近再分为N份,重新旋转求最优值。取N1000, M10即可获得精确值。

 

//0-90度范围内三分旋转的角度

//旋转公式:x’=x*cos(phi)-y*sin(phi)    y’=x*sin(phi)+y*cos(phi)

#include

#include

#include

using namespace std;

struct point

{

   double x,y;

}p[31];

int n;

const double pi=acos(-1.0);

const double eps=1e-4;

double area(double a)

{

   return a*a;

}

double max(double a,double b)

{

   return a>b?a:b;

}

//求面积

double cal(double z)

{

   int i;

   double x,y;

   double max_x=-10000.0,max_y=-10000.0,min_x=10000.0,min_y=10000.0;

   for(i=0;i

   {

       x=p[i].x*cos(z)-p[i].y*sin(z);

       y=p[i].x*sin(z)+p[i].y*cos(z);

       if(max_x

           max_x=x;

       if(max_y

           max_y=y;

       if(min_x>x)

           min_x=x;

       if(min_y>y)

           min_y=y;

   }

   return max(area(max_x-min_x),area(max_y-min_y));

}

//三分

double div()

{

   double left=0,right=pi/2.0;

   double ans1,ans2;

   double m,mm;

   do

   {

       m=(left+right)/2.0;

       mm=(right+m)/2.0;

       ans1=cal(m);

       ans2=cal(mm);

       if(ans1

           right=mm;

       else

           left=m;

   }while(fabs(ans1-ans2)>eps);

   return ans1;

}

int main(){

    //freopen("C:\\Users\\Administrator\\Desktop\\001.txt","r",stdin);

    int t;

    scanf("%d",&t);

    while(t--)

    {

        scanf("%d",&n);

        int i;

        for(i=0;i

            scanf("%lf%lf",&p[i].x,&p[i].y);

        printf("%.2lf\n",div());

    }

    return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值