POJ 3301 Texas Trip(最小正方形覆盖、点坐标旋转)

题目链接:
POJ 3301 Texas Trip
题意:
平面给 n 个整数点,求覆盖这n个整数点的最小正方形面积?
数据范围: n30,500
分析:
先考虑如果水平竖直地放置正方形(边和坐标轴平行)圈住所有点的最小正方形的边长是:

L=max(xmaxxmin,ymaxymin)

根据经验(?):如果旋转正方形,可以发现覆盖这 n 个点的最小正方形面积是先减后增的。符合凸性函数的性质,所以我们可以枚举旋转的角度。
但是枚举角度计算正方形的话比较麻烦,可以选择旋转平面上的点,使得正方形仍然是水平竖直放置的,因为这样计算正方形的边长比较方便。
如果把点表示成极坐标形式:
x=r×cosθ,y=r×sinθ,r=x2+y2θ

那么顺时针旋转 α 角度后:
x=r×cos(θα),y=r×sin(θα)

化简一下可得:
x=r×cosθ×cosα+r×sinθ×sinα=x×cosα+y×sinα

y=r×sinθ×cosαr×cosθ×sinα=y×cosαx×sinα

这样子我们就得到了旋转后的坐标,计算此时的最小正方形,三分角度,比较 mid midmid 即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
const int MAX_N = 50;
const double eps = 1e-12;
const double pi = acos(-1.0);

int n, T;
double x[MAX_N], y[MAX_N];

double rotate(double alp)
{
    double Minx = 1e5, Miny = 1e5, Maxx = -1.0, Maxy = -1.0, tmpx, tmpy;
    for(int i = 0; i < n; ++i) {
        tmpx = x[i] * cos(alp) + y[i] * sin(alp);
        tmpy = y[i] * cos(alp) - x[i] * sin(alp);
        Minx = min(Minx, tmpx), Miny = min(Miny, tmpy);
        Maxx = max(Maxx, tmpx), Maxy = max(Maxy, tmpy);
    }
    double len = max(Maxx - Minx, Maxy - Miny);
    return len * len;
}

int main()
{
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        for(int i = 0; i < n; ++i) {
            scanf ("%lf%lf", x + i, y + i);
        }
        double low = 0.0, high = pi / 2.0, mid, midmid, res1, res2;
        for(int i = 0; i < 100; ++i) {
            mid = (low + high) / 2.0;
            midmid = (high + mid) / 2.0;
            res1 = rotate(mid);
            res2 = rotate(midmid);
            if(res1 < res2) high = midmid;
            else low = mid;
        } 
        printf("%.2lf\n", rotate(mid));
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值