zoukankan      html  css  js  c++  java
  • HDU 5251 矩形面积 (旋转卡壳)

    2015年百度之星程序设计大赛 - 初赛(1) 1006

    比赛链接:2015年百度之星程序设计大赛 - 初赛(1)

    题目链接:HDU 5251

    Problem Description

    小度熊有一个桌面,小度熊剪了很多矩形放在桌面上,小度熊想知道能把这些矩形包围起来的面积最小的矩形的面积是多少。

    Input

    第一行一个正整数 (T),代表测试数据组数 ((1le Tle 20)),接下来 (T) 组测试数据。

    每组测试数据占若干行,第一行一个正整数 (N(1le Nle 1000)),代表矩形的数量。接下来 (N) 行,每行 (8) 个整数 (x1,y1,x2,y2,x3,y3,x4,y4),代表矩形的四个点坐标,坐标绝对值不会超过10000。

    Output

    对于每组测试数据,输出两行:

    第一行输出"Case #i:",i 代表第 i 组测试数据。

    第二行包含1 个数字,代表面积最小的矩形的面积,结果保留到整数位。

    Sample Input

    2
    2
    5 10 5 8 3 10 3 8
    8 8 8 6 7 8 7 6
    1
    0 0 2 2 2 0 0 2
    

    Sample Output

    Case #1:
    17
    Case #2:
    4
    

    Solution

    旋转卡壳

    思路见这里:洛谷 P3187 BZOJ 1185 [HNOI2007]最小矩形覆盖 (旋转卡壳)

    杭电就比较良心了,没有卡精度。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const double eps = 1e-8;
    const int maxn = 100000 + 5;
    
    int n;
    
    inline int dcmp(double x) {
        if(fabs(x) < eps) return 0;
        return x > 0? 1: -1;
    }
    
    class Point {
    public:
        double x, y;
        Point(double x = 0, double y = 0) : x(x), y(y) {}
        Point operator+(Point a) {
            return Point(a.x + x, a.y + y);
        }
        Point operator-(Point a) {
            return Point(x - a.x, y - a.y);
        }
        bool operator<(const Point &a) const {
            if (x == a.x)
                return y < a.y;
            return x < a.x;
        }
        Point operator*(double a) {
            return Point(x * a, y * a);
        }
        bool operator==(const Point &a) const {
            if (x == a.x && y == a.y)
                return 1;
            return 0;
        }
        double len() {
            return sqrt(x * x + y * y);
        }
        double dis2(const Point a) {
            return pow(x - a.x, 2) + pow(y - a.y, 2);
        }
        double dis(const Point a) {
            return sqrt(dis2(a));
        }
    };
    
    Point ans[10];
    
    typedef Point Vector;
    
    double cross(Vector a, Vector b) {
        return a.x * b.y - a.y * b.x;
    }
    
    double dot(Vector a, Vector b) {
        return a.x * b.x + a.y * b.y;
    }
    
    typedef vector<Point> Polygon;
    Polygon Andrew(Polygon P) {
        int n = P.size(), k = 0;
        vector<Point> H(2 * n);
        sort(P.begin(), P.end());
        for (int i = 0; i < n; ++i) {
            while (k >= 2 && cross(H[k - 1] - H[k - 2], P[i] - H[k - 2]) < eps) {
                k--;
            }
            H[k++] = P[i];
        }
        int t = k + 1;
        for (int i = n - 1; i > 0; --i) {
            while (k >= t && cross(H[k - 1] - H[k - 2], P[i - 1] - H[k - 2]) < eps) {
                k--;
            }
            H[k++] = P[i - 1];
        }
        H.resize(k - 1);
        return H;
    }
    
    double rotating_caliper(Polygon v) {
        double min_s = 1e18;
    	int cnt = v.size();
        v.push_back(v[0]);
        int u = 1, r = 1, l = 1;
        for (int i = 0; i < cnt; ++i) {
            // 最上面的点
            while (dcmp(fabs(cross(v[u] - v[i], v[i + 1] - v[i])) - fabs(cross(v[u + 1] - v[i], v[i + 1] - v[i]))) <= 0) {
                u = (u + 1) % cnt;
            }
    
            // 最右边的点
            while (dcmp(dot(v[r] - v[i], v[i + 1] - v[i]) - dot(v[r + 1] - v[i], v[i + 1] - v[i])) <= 0) {
                r = (r + 1) % cnt;
            }
    
            if(!i) l = r;
    
            // 最左边的点
            while (dcmp(dot(v[l] - v[i], v[i + 1] - v[i]) - dot(v[l + 1] - v[i], v[i + 1] - v[i])) >= 0) {
                l = (l + 1) % cnt;
            }
            double d = v[i].dis(v[i + 1]);
            double R = dot(v[r] - v[i], v[i + 1] - v[i]) / d; 
            double L = dot(v[l] - v[i], v[i + 1] - v[i]) / d;
            double ll = R - L;
            double dd = fabs(cross(v[u] - v[i], v[i + 1] - v[i])) / d;
            min_s = min(min_s, ll * dd);
        }
        return min_s;
    }
    
    int main() {
        int T;
        scanf("%d", &T);
        for(int _ = 1; _ <= T; ++_) {
            scanf("%d", &n);
            Polygon s;
            for(int i = 0; i < n * 4; ++i) {
                Point p;
                scanf("%lf%lf", &p.x, &p.y);
                s.push_back(p);
            }
            Polygon p = Andrew(s);
            double d = rotating_caliper(p);
            printf("Case #%d:
    %.0lf
    ", _, d);
        }
        
        return 0;
    }
    
  • 相关阅读:
    如何将Superset嵌入后台系统之实践
    如何将Superset嵌入后台系统之实践
    SQL server添加链接服务器脚本
    面试题:JQuery有几种选择器?
    数据库增加索引
    Mybatis与Ibatis比较
    jQuery 选择器
    Form 和 Input 对象
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
  • 原文地址:https://www.cnblogs.com/wulitaotao/p/11435690.html
Copyright © 2011-2022 走看看