poj3301(三分-坐标旋转)

题意:给出最多30个点的坐标,求覆盖所有点的最小正方形面积。


解法:没有证明正确性,网上对于此法的正确性有争议。反正是用三分过的,也许数据弱了。就是在0-90度的旋转范围内三分角度(所有点旋转的角度)。正方形的边总是平行于坐标轴的,那么每次正方形的边长总是最大x坐标之差和最大y坐标之差中更大那个。

      点旋转A后的坐标公式

                                             X1=cos(A)*X0 - sin(A)*Y0;

                                             Y1=sin(A)*X0 + cos(A)*Y0;

代码:

/****************************************************
* author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>

using namespace std;

#define sz(c) ((int)(c).size())
#define   forl(i, a, b) for(int i = (a); i <  (b); ++i)
#define  forle(i, a, b) for(int i = (a); i <= (b); ++i)
#define repc(n) for(int repp_b = (n), repp = 0; repp < repp_b; ++repp)
#define rst(a, v) memset(a, v, sizeof a)
#define eps 1e-8
#define INF (1<<29)
#define LL __int64
inline int     rdi() { int d; scanf("%d", &d); return d; }
inline char    rdc() { scanf(" "); return getchar(); }
inline void     rds(char *s) {scanf("%s", s); }
inline double rddb() { double d; scanf("%lf", &d); return d; }


struct point
{
    double x,y;
} points[50];
int n;
double make(double angle)
{
    double maxx=-10000,minx=10000,maxy=-10000,miny=10000;
    forl(i,0,n)
    {
      point p;
      p.x=points[i].x*cos(angle)-sin(angle)*points[i].y;
       p.y=points[i].x*sin(angle)+cos(angle)*points[i].y;
       maxx=max(maxx,p.x);
       minx=min(minx,p.x);
       maxy=max(maxy,p.y);
       miny=min(miny,p.y);
    }
    return max(maxx-minx,maxy-miny);
}

int main()
{
   repc(rdi()){
       n=rdi();
       forl(i,0,n){
           points[i].x=rddb(),points[i].y=rddb();//cout<<points[i].y<<endl;
       }
       double left=0,right=acos(-1)/2;
       while(right-left>=0.00000001)
       {
           //cout<<left<<endl;
           double middle=(left+right)/2;
           double middleagain=(middle+right)/2;
           if(make(middle)<make(middleagain))
            right=middleagain;
           else
            left=middle;
       }
       printf("%.2f\n",make(left)*make(left));
   }
   return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值