zoukankan      html  css  js  c++  java
  • UVA 10173 Smallest Bounding Rectangle (求凸包最小面积外接矩阵、旋转卡壳)

    题目:传送门

    思路:

    计算过程出处:

    1. 计算全部四个多边形的端点, 称之为 xminP, xmaxP, yminP, ymaxP
    2. 通过四个点构造 P 的四条切线。 他们确定了两个“卡壳”集合。
    3. 如果一条(或两条)线与一条边重合, 那么计算由四条线决定的矩形的面积, 并且保存为当前最小值。 否则将当前最小值定义为无穷大。
    4. 顺时针旋转线直到其中一条和多边形的一条边重合。
    5. 计算新矩形的面积, 并且和当前最小值比较。 如果小于当前最小值则更新, 并保存确定最小值的矩形信息。
    6. 重复步骤4和步骤5, 直到线旋转过的角度大于90度。
    7. 输出外接矩形的最小面积。
    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <vector>
    #include <set>
    #include <string>
    #include <math.h>
    #define LL long long
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF INT_MAX
    #define inf LLONG_MAX
    #define PI acos(-1)
    using namespace std;
    
    const int N = 5e5 + 5;
    
    struct Point {
        double x, y;
        Point(double x = 0, double y = 0) : x(x), y(y) { } /// 构造函数
    };
    
    typedef Point Vector;
    /// 向量+向量=向量, 点+向量=向量
    Vector operator + (Vector A, Vector B) { return Vector(A.x + B.x, A.y + B.y); }
    ///点-点=向量
    Vector operator - (Point A, Point B) { return Vector(A.x - B.x, A.y - B.y); }
    ///向量*数=向量
    Vector operator * (Vector A, double p) { return Vector(A.x * p, A.y * p); }
    ///向量/数=向量
    Vector operator / (Vector A, double p) { return Vector(A.x / p, A.y / p); }
    
    const double eps = 1e-8;
    int dcmp(double x) {
        if(fabs(x) < eps) return 0; else return x < 0 ? -1 : 1;
    }
    
    bool operator < (const Point& a, const Point& b) {
        return a.x == b.x ? a.y < b.y : a.x < b.x;
    }
    
    bool operator == (const Point& a, const Point &b) {
        return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
    }
    
    double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; } /// 点积
    double Length(Vector A) { return sqrt(1.0 * Dot(A, A)); } /// 计算向量长度
    double Angle(Vector A, Vector B) { return acos(Dot(A, B) / Length(A) / Length(B)); } /// 向量A、B夹角
    double Cross(Vector A, Vector B) { return A.x*B.y - A.y*B.x; } /// 叉积
    
    int ConvexHull(Point* p, int n, Point* ch) {
        sort(p, p + n);
        int m = 0;
        rep(i, 0, n - 1) {
            while(m > 1 && Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2]) <= 0) m--;
            ch[m++] = p[i];
        }
        int k = m;
        dep(i, 0, n - 2) {
            while(m > k && Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2]) <= 0) m--;
            ch[m++] = p[i];
        }
        if(n > 1) m--;
        return m;
    }
    
    double PTS(Point p, Point A, Point B) { /// 求点 p 到线段 AB 的最短距离
        if(A == B) return Length(p - A);
        Point v1 = B - A, v2 = p - A, v3 = p - B;
        if(dcmp(Dot(v1, v2)) < 0) return Length(v2);
        else if(dcmp(Dot(v1, v3)) > 0) return Length(v3);
        else return fabs(Cross(v1, v2)) / Length(v1);
    }
    /* 平行线段 a1a2 和 b1b2 的距离 */
    double DS(Point a1, Point a2, Point b1, Point b2) {
        return min(PTS(b1, a1, a2), min(PTS(b2, a1, a2), min(PTS(a1, b1, b2), PTS(a2, b1, b2))));
    }
    
    /* 得到向量 a1a2 和 b1b2 的位置关系 */
    double Get_angle(Point a1, Point a2, Point b1, Point b2) {
        Point t = b1 - (b2 - a1);
        return Cross(a2 - a1, t - a1);
    }
    
    double Rotating_calipers(Point P[], int n) {
    
        double ans = 1e99;
        int t, l, r;
        t = r = 1;
    
        if(n < 3) return 0;
    
        rep(i, 0, n - 1) {
    
            while(dcmp(Cross(P[(i + 1) % n] - P[i], P[(t + 1) % n] - P[i]) - Cross(P[(i + 1) % n] - P[i], P[t] - P[i])) > 0) ///确定对踵点
                t = (t + 1) % n;
            while(dcmp(Dot(P[(i + 1) % n] - P[i], P[(r + 1) % n] - P[i]) - Dot(P[(i + 1) % n] - P[i], P[r] - P[i])) > 0) ///确定离 p[i] 最右的那个点
                r = (r + 1) % n;
            if(i == 0) l = r;
            while(dcmp(Dot(P[(i + 1) % n] - P[i], P[(l + 1) % n] - P[i]) - Dot(P[(i + 1) % n] - P[i], P[l] - P[i])) <= 0)///离p[i]最左的那个点
                l = (l + 1) % n;
    
            double Len = Length(P[(i + 1) % n] - P[i]);
            /// 通过p[i]和p[i+1]和p[t](对踵点)确定的三角形的面积的两倍除以底边p[i]p[i+1]就是高了,这个高就是矩形的长
            ///宽度,可以通过最右边那个点在p[i]p[i+1]的投影加上最左边那个点在p[i]p[i+1]的投影就是宽了,代码写的是减,因为一正一负
            double tmp = Cross(P[(i + 1) % n] - P[i], P[t] - P[i]) * (Dot(P[(i + 1) % n] - P[i], P[r] - P[i]) - Dot(P[(i + 1) % n] - P[i], P[l] - P[i])) / Len / Len;
            ans = min(ans, tmp);
        }
        return ans;
    }
    
    Point P[N], Q[N];
    
    int main() {
        int n, m;
        while(scanf("%d", &n) && n) {
    
            rep(i, 0, n - 1) scanf("%lf %lf", &P[i].x, &P[i].y);
    
            n = ConvexHull(P, n, Q);
    
            printf("%.4f
    ", Rotating_calipers(Q, n));
        }
        return 0;
    }
    一步一步,永不停息
  • 相关阅读:
    [LeetCode]2. Add Two Numbers链表相加
    Integration between Dynamics 365 and Dynamics 365 Finance and Operation
    向视图列添加自定义图标和提示信息 -- PowerApps / Dynamics365
    Update the Power Apps portals solution
    Migrate portal configuration
    Use variable to setup related components visible
    Loyalty management on Retail of Dynamic 365
    Modern Fluent UI controls in Power Apps
    Change screen size and orientation of a canvas app in Power App
    Communication Plan for Power Platform
  • 原文地址:https://www.cnblogs.com/Willems/p/12507853.html
Copyright © 2011-2022 走看看