uva 12307(点集的外接矩形)

题意:平面上有n个点,要求求出包含所有点的矩形的最小面积和最小周长。
题解:先求点集的凸包,然后把凸包的每条边当做底边,把其他左、上、右三边根据底边用旋转卡壳的方式确定,计算长宽更新最小值。做了这题后对旋转卡壳理解更深刻了。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
const double eps = 1e-11;
const double PI = acos(-1);

int dcmp(double x) {
    if (fabs(x) < eps)
        return 0;
    return x > 0 ? 1 : -1;
}
struct Point {
    double x, y;
    Point (double a = 0, double b = 0): x(a), y(b) {}
};
typedef Point Vector;
typedef vector<Point> Polygon;

Vector operator + (const Vector& a, const Vector& b) { return Vector(a.x + b.x, a.y + b.y); }
Vector operator - (const Vector& a, const Vector& b) { return Vector(a.x - b.x, a.y - b.y); }
Vector operator * (const Vector& a, double& b) { return Vector(a.x * b, a.y * b); }
Vector operator / (const Vector& a, double& b) { return Vector(a.x / b, a.y / b); }
bool operator == (const Vector& a, const Vector& b) { return !dcmp(a.x - b.x) && !dcmp(a.y - b.y); }
bool operator < (const Vector& a, const Vector& b) { return a.x < b.x || (a.x == b.x && a.y < b.y); }
double Dot(const Vector& a, const Vector& b) { return a.x * b.x + a.y * b.y; }
double Length(const Vector& a) { return sqrt(Dot(a, a)); }
double Length2(const Vector& a) { return Dot(a, a); }
double Cross(const Vector& a, const Vector& b) { return a.x * b.y - a.y * b.x; }
double Angle(const Vector& a, const Vector& b) { return acos(Dot(a, b) / Length(a) / Length(b)); }
Vector Rotate(Vector A, double rad) { return Point(A.x * cos(rad) - A.y * sin(rad), A.x * sin(rad) + A.y * cos(rad)); }

int ConvexHull(Point* P, int cnt, Point* res) {
    sort(P, P + cnt);
    cnt = unique(P, P + cnt) - P;
    int m = 0;
    for (int i = 0; i < cnt; i++) {
        while (m > 1 && Cross(res[m - 1] - res[m - 2], P[i] - res[m - 2]) <= 0)
            m--;
        res[m++] = P[i];
    }
    int k = m;
    for (int i = cnt - 2; i >= 0; i--) {
        while (m > k && Cross(res[m - 1] - res[m - 2], P[i] - res[m - 2]) <= 0)
            m--;
        res[m++] = P[i];
    }
    if (cnt > 1)
        m--;
    return m;
}

void GetMinRCarea(Point* P, int cnt, double& S, double& C) {
    S = C = 1e18;
    int l = 1, r = 1, u = 1;
    for (int i = 0; i < cnt; i++) { //枚举底边P[i]~P[i+1]
        while (Cross(P[i + 1] - P[i], P[u + 1] - P[u]) > eps)
            u = (u + 1) % cnt;//找上边,夹角还能增加就向后找
        while (Dot(P[i + 1] - P[i], P[r + 1] - P[r]) > eps) 
            r = (r + 1) % cnt;//找右边,夹角还小于90°就继续找
        if (i == 0)
            l = (r + 1) % cnt;
        while (Dot(P[i + 1] - P[i], P[l + 1] - P[l]) < -eps)
            l = (l + 1) % cnt;//找左边,夹角还大于90°就继续找
        double d = Length(P[i + 1] - P[i]); //底边长度
        double a = Cross(P[i + 1] - P[i], P[u] - P[i]) / d;//叉积几何意义就是求向量组成的平行四边形面积,除以底边就是高
        double b = (Dot(P[r] - P[i], P[i + 1] - P[i]) - Dot(P[l] - P[i], P[i + 1] - P[i])) / d;//向左向右的投影和(点积几何意义:A*B = |A||B|cosθ一个向量在另一个向量方向上的投影长度乘后者的长度),所以最后还要除后者的长度。
        S = min(S, a * b);
        C = min(C, 2.0 * (a + b));
    }
}
const int N = 100005;
Point P[N], R[N];
int n;

int main() {
    while(scanf("%d", &n) == 1 && n) {
        for (int i = 0; i < n; i++)
            scanf("%lf%lf", &R[i].x, &R[i].y);
        int cnt = ConvexHull(R, n, P);
        P[cnt] = P[0];
        double S, C;
        GetMinRCarea(P, cnt, S, C);
        printf("%.2lf %.2lf\n", S, C);
    }
    return 0;
}
在MATLAB中,计算点集的最小外接矩形通常是为了找到包含所有数据点的最小边界矩形,这个矩形的边长应该尽可能小。可以使用`minrect`函数或者通过编程的方式来实现这一功能。 以下是基本步骤: 1. 准备一个二维点集,例如`points = [x1, y1; x2, y2; ...; xn, yn]`,其中每个元素是一对坐标(x, y)。 2. 使用`polyfit`或`fitline`函数找到通过这些点的一组直线(可能是x轴、y轴或者对角线),这将帮助确定矩形的两个相对边缘。 3. 对于每一对平行边,遍历所有点并找出沿该方向的最大值和最小值,这将是矩形的长度。 4. 计算出宽度(垂直边的长度)和高度(水平边的长度)。 5. 使用`rotatematrix`和点集的最左下角点(或其他任一点作为参照点)来构造最小外接矩形。 ```matlab % 假设我们有一个点集points [numPoints, 2] = size(points); % 取第一行作为初始参照点 refPoint = points(1,:); % 计算x轴和y轴的极限 xMax = max(points(:,1)); xMin = min(points(:,1)); yMax = max(points(:,2)); yMin = min(points(:,2)); % 构造最小外接矩形 [x, y] = meshgrid(xMin:xMax, yMin:yMax); mask = polyval(polyfit(points(:,1), points(:,2), 1), x, y) == refPoint(2); [~, idx] = min(y(~mask)); % 找到y轴的最低点 rectangleEdgeY = y(idx); [~, idx] = min(x(~mask)); % 找到x轴的最低点 rectangleEdgeX = x(idx); % 创建旋转矩阵 rotationMatrix = [1, 0; -1 / rectangleEdgeX, 1]; % 转换为新的坐标系,得到最小外接矩形 transformedPoints = points * rotationMatrix; minRectPoints = transformedPoints([1 end], :); % 最左下和右上角点 % 结果显示或保存 disp(minRectPoints); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值