0
点赞
收藏
分享

微信扫一扫

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]))

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

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

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

//在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;

}

举报

相关推荐

0 条评论