旋转卡壳(Rotating Calipers )

#include <cstdio>
#include <cfloat>
#include <cmath>
#include <algorithm>

const int MAXN = 50005;
const double EPS = 1e-9;

struct Point {
    double x, y;

    Point(double x = 0, double y = 0) : x(x), y(y) {}

    bool operator<(const Point &rhs) const { return x == rhs.x ? y < rhs.y : x < rhs.x; }

    Point operator+(const Point &rhs) const { return Point(x + rhs.x, y + rhs.y); }
    Point operator-(const Point &rhs) const { return Point(x - rhs.x, y - rhs.y); }
    Point operator*(const double a) const { return Point(x * a, y * a); }
    Point operator/(const double a) const { return Point(x / a, y / a); }
    friend double dot(const Point &a, const Point &b) { return a.x * b.x + a.y * b.y; }
    friend double cross(const Point &a, const Point &b) { return a.x * b.y - a.y * b.x; }

    friend double dist(const Point &a, const Point &b) {
        return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }

    void print() {
        if (std::abs(x) <= EPS) x = 0;
        if (std::abs(y) <= EPS) y = 0;
        printf("%.5f %.5f\n", x, y);
    }

    Point getPerpendicular() {
        double X = sqrt(1 / (1 + (x / y) * (x / y)));

        int sx, sy;
        if (x > 0 && y > 0) sx = 1, sy = -1;
        else if (x > 0 && y <= 0) sx = 1, sy = 1;
        else if (x <= 0 && y > 0) sx = -1, sy = -1;
        else sx = 1, sy = -1;

        return Point(sx * X, sy * std::sqrt(1 - X * X));
    }    
} P[MAXN], ch[MAXN];

struct Rectangle {
    Point p[4];

    void print() {
        int temp = 0;
        for (int i = 1; i < 4; i++)
            if (p[i].y < p[temp].y || (p[i].y == p[temp].y && p[i].x < p[temp].x)) temp = i;
        for (int i = 0; i < 4; i++) p[(i + temp) % 4].print();
    }

    Point &operator[](int i) { return p[i]; }
};

int getConvexHull(int n) {
    std::sort(P + 1, P + n + 1);

    int m = 0;
    for (int i = 1; i <= n; i++) {
        while (m > 1 && cross(ch[m - 1] - ch[m - 2], P[i] - ch[m - 2]) <= 0) m--;
        ch[m++] = P[i];
    }

    int k = m;
    for (int i = n; i; i--) {
        while (m > k && cross(ch[m - 1] - ch[m - 2], P[i] - ch[m - 2]) <= 0) m--;
        ch[m++] = P[i];
    }

    m > 1 ? m-- : 0;
    return m;
}

Rectangle ans;
double ansArea = DBL_MAX;
void rotatingCalipers(int n) {
    for (int curr = 0, right = 1, up = 1, left = 1; curr < n; curr++) {
        while (dot(ch[curr + 1] - ch[curr], ch[right + 1] - ch[right]) >= 0)
            right = (right + 1) % n;

        curr ? 0 : up = right;
        while (cross(ch[curr + 1] - ch[curr], ch[up + 1] - ch[up]) >= 0)
            up = (up + 1) % n;

        curr ? 0 : left = up;
        while (dot(ch[curr + 1] - ch[curr], ch[left + 1] - ch[left]) <= 0)
            left = (left + 1) % n;

        Point currV = ch[curr + 1] - ch[curr];
        double currLen = dist(ch[curr], ch[curr + 1]);
        double height = std::abs(cross(currV, ch[up] - ch[curr]) / currLen);
        double bottom = std::abs(dot(currV, ch[left] - ch[curr]) / currLen)
                      + std::abs(dot(currV, ch[right] - ch[curr]) / currLen);

        double currArea = bottom * height;
        Point currPerpendicular = currV.getPerpendicular();

        if (currArea < ansArea) {
            ansArea = currArea;
            ans[0] = ch[curr] + currV * fabs((dot(currV, ch[right] - ch[curr])) / currLen) / currLen;
            ans[1] = ans[0] + currPerpendicular * height;
            ans[2] = ans[1] - currV * bottom / currLen;
            ans[3] = ans[2] - currPerpendicular * height;
        }
    }
}

int main() {
    int n;
    scanf("%d", &n);

    for (int i = 1; i <= n; i++) scanf("%lf %lf", &P[i].x, &P[i].y);

    int m = getConvexHull(n);
    rotatingCalipers(m);

    printf("%.5f\n", ansArea);
    ans.print();

    return 0;
}

results matching ""

    No results matching ""