UVA10173 Smallest Bounding Rectangle 最小面积矩形覆盖

\(\color{#0066ff}{题目描述}\)

给定n(>0)二维点的笛卡尔坐标,编写一个程序,计算其最小边界矩形的面积(包含所有给定点的最小矩形)。

输入文件可以包含多个测试样例。每个测试样例从包含一个正数的行开始。 整数N(<1001),表示该测试样例中的点的数量。接下来的n行各包含两个实数,分别给出一个点的x和y坐标。输入最后包含一个值为0的测试样例,该值必须不被处理。

对于输入中的每个测试样例都输出一行,包含最小边界矩形的面积,小数点后四舍五入到第四位。

\(\color{#0066ff}{输入格式}\)

\(\color{#0066ff}{输出格式}\)

\(\color{#0066ff}{输入样例}\)

3
-3.000 5.000
7.000 9.000
17.000 5.000
4
10.000 10.000
10.000 20.000
20.000 20.000
20.000 10.000
0

\(\color{#0066ff}{输出样例}\)

80.0000
100.0000

\(\color{#0066ff}{数据范围与提示}\)

none

\(\color{#0066ff}{题解}\)

旋转卡壳

首先先求一遍凸包

对于最小面积外接矩形,显然至少有一条边与凸包重合,就枚举那条边(底边)

对于上面的边,通过叉积叉出面积判断最高位置,找到上边

对于左边,用点积,找到最大点积(投影最长,那么最靠左),右边指针从左边开始找投影最短

每次移动底边,然后更新上左右,来更新ans

#include <bits/stdc++.h>
#define _ 0
#define LL long long
inline LL in() {
    LL x = 0, f = 1; char ch;
    while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    while(isdigit(ch)) x = x * 10 + (ch ^ 48), ch = getchar();
    return x * f;
}

struct node {
    double x,y;
    node(double x = 0, double y = 0):x(x), y(y) {}
    node operator - (const node &b) const {
        return node(x - b.x, y - b.y);
    }
    double operator ^ (const node &b) const {
        return x * b.y - y * b.x;
    }
    double operator * (const node &b) const {
        return x * b.x + y * b.y;
    }
    double mo() {
        return sqrt(x * x + y * y);
    }
    double jj() const {
        return atan2(y, x);
    }
};
const int maxn = 10005;
node e[maxn], v[maxn];
int n,top;

double S(node a,node b,node c) {
    return (b - a) ^ (c - a);
}

bool cmp(const node &a, const node &b) {
    return (a.jj() < b.jj() || (a.jj() == b.jj() && (a - e[0]).mo() < (b - e[0]).mo()));
}
void tubao() {
    int min = 0;
    for(int i = 0; i < n; i++) 
        if(e[i].y < e[min].y || (e[i].y == e[min].y && e[i].x < e[min].x)) min = i;
    std::swap(e[0], e[min]);
    for(int i = 1; i < n; i++) e[i] = e[i] - e[0];
    e[0] = 0;
    std::sort(e + 1, e + n, cmp);
    v[0] = e[0], v[1] = e[1];
    for(int i = top = 2; i < n; i++) {
        while((top > 1) && (S(v[top - 2], v[top - 1], e[i]) <= 0)) top--;
        v[top++] = e[i];
    }
    v[top] = e[0];
}

double C(node a,node b,node c) {
    return (c - a) * (b - a);
}

double rotate()
{
    if(top < 3) return 0;
    int l = 1, u = 1, r;
    double a, b, c, ans = 1e20;
    for(int i = 0; i < top; i++) {
        while(S(v[i], v[i + 1], v[u + 1]) > S(v[i], v[i + 1], v[u])) u = (u + 1) % top;
        while(C(v[i], v[i + 1], v[l + 1]) > C(v[i], v[i + 1], v[l])) l = (l + 1) % top;
        if(!i) r = l;
        while(C(v[i], v[i + 1], v[r + 1]) <= C(v[i], v[i + 1], v[r])) r = (r + 1) % top;
        a = S(v[i], v[i + 1], v[u]);
        b = C(v[i], v[i + 1], v[l]) - C(v[i], v[i + 1], v[r]);
        c = C(v[i], v[i + 1], v[i + 1]);
        ans = std::min(ans, a * b / c);
    }
    return ans;
}

int main() {
    while("fuck") {
        n = in();
        if(!n) break;
        for(int i = 0; i < n; i++) scanf("%lf%lf", &e[i].x, &e[i].y);
        tubao();
        printf("%.4lf\n", rotate());
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/olinr/p/10197359.html
今日推荐