POJ3301

Problem: Texas Trip
Description: 给你一些点的集合,让你用一个最小的正方形来覆盖所有的点,求这个正方形的面积。
Solution: 三分求极值+图形旋转。我们知道,求最小正方形也就是求最小边长,如果这个正方形是平行于X轴的,那么最小边长就是任意两个点横向和纵向的最大值。那么我们要绕原点旋转这些点,这个其实也可以看成是正方形绕这些点旋转。那么我们对于旋转了rad度的这些点。求得横向坐标和纵向坐标的最大值也就是当前的正方形边长。坐标变换公式:

X=xsin(rad)ycos(rad)
Y=xcos(rad)+ysin(rad)

可以观察到这是一个凹函数,那么对于这种函数我们可以用三分来求得极值。这是必须的。

对于这个题。我们求最小值。那么就是当mid比mmid更靠近也就是cal(mid) < cal(mmid)时r=mmid。不懂的可以百度三分算法。

Code(C++):

#include <stdio.h>
#include <string.h>
#include <math.h>

#define MIN(a,b) ((a)>(b)? (b):(a))
#define MAX(a,b) ((a)<(b)? (b):(a))

const int M=35;

const double PI=4*atan(1.0);
const double EPS=1e-10;

typedef struct tagPoint{
    int x,y;
}Point;

int n;

Point points[M];

double cal(double rad)
{
    double ans=0;
    double SIN=sin(rad);
    double COS=cos(rad);
    for(int i=0;i<n-1;i++)
        for(int j=i+1;j<n;j++){
            double tmp1=fabs((points[i].x-points[j].x+0.0)*COS-(points[i].y-points[j].y+0.0)*SIN);
            double tmp2=fabs((points[i].x-points[j].x+0.0)*SIN+(points[i].y-points[j].y+0.0)*COS);
            ans=MAX(ans,MAX(tmp1,tmp2));
        }
    return ans;
}

double deal()
{
    double l=0,r=PI,mid,mmid;
    while(fabs(r-l)>EPS){
        mid=(r+l)/2;
        mmid=(mid+r)/2;
        //fabs(cal(mid)-cal(mmid))<EPS? r=mmid:l=mid;
        cal(mid)<cal(mmid)? r=mmid:l=mid;
    }
    return cal(l)*cal(l);
}

int main()
{
    int N;
    for(scanf("%d",&N);N--;){
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d%d",&points[i].x,&points[i].y);

        double ans=deal();

        printf("%.2f\n",ans);
    }
    return 0;
}

你可能感兴趣的:(C语言,poj)