计算几何们

该博客主要介绍了一种算法,用于求解二维平面上一组点构成的最大最小凸包上的三角形面积。通过以y轴负半轴为极轴排序点,然后遍历所有二元组的边来找到最小和最大的三角形面积。算法中使用了点的叉乘和点乘来判断边的位置关系,并进行了排序和交换操作以确保正确性。最终,博主给出了完整的C++代码实现。
摘要由CSDN通过智能技术生成

求最大最小凸包上三角形面积,可以考虑以y轴负半轴为极轴,进行排序,排序之后从小到大遍历所有二元组的边,此时直接对x坐标排序,接近的点一定是高最小的点,之后记得swap一下,因为画图可知此时两边的顺序倒了过来

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

using _T = LL; 

constexpr _T eps = 0;
constexpr long double PI = 3.1415926535897932384l;

template <typename T> 
struct point
{
    T x, y;

    point() {}
    point(T x, T y) : x(x), y(y) {}
    bool operator==(const point &a) const { return (abs(x - a.x) <= eps && abs(y - a.y) <= eps); }
    bool operator<(const point &a) const { if (abs(x - a.x) <= eps) return y < a.y - eps; return x < a.x - eps; }
    bool operator>(const point &a) const { return !(*this < a || *this == a); }
    point operator+(const point &a) const { return {x + a.x, y + a.y}; }
    point operator-(const point &a) const { return {x - a.x, y - a.y}; }
    point operator-() const { return {-x, -y}; }
    point operator*(const T k) const { return {k * x, k * y}; }
    point operator/(const T k) const { return {x / k, y / k}; }
    T operator*(const point &a) const { return x * a.x + y * a.y; } // 点乘 Dot
    T operator^(const point &a) const { return x * a.y - y * a.x; } // 叉乘 Cross
    // 1:左  -1:右  0:线上
    // auto的原理就是根据后面的值,来自己推测前面的类型是什么。
    // return *this返回当前对象,return this返回当前对象的地址(指向当前对象的指针)
    int toleft(const point &a) const { const auto t = (*this) ^ a; return (t > eps) - (t < -eps); }
    T len2() const { return (*this) * (*this); }
    T dis2(const point &a) const { return (a - (*this)).len2(); }
    double len() const { return sqrt(len2()); }
    double dis(const point &a) const { return sqrt(dis2(a)); }
    // 夹角
    double ang(const point &a) const { return acos(max(-1.0, min(1.0, ((*this) * a) / (len() * a.len())))); }
    // 逆时针旋转rad
    point rot(const double rad) const { return {x * cos(rad) - y * sin(rad), x * sin(rad) + y * cos(rad)}; }
    point rot(const double cosr, const double sinr) const { return {x * cosr - y * sinr, x * sinr + y * cosr}; }
};

using Point = point<_T>;
typedef Point Vector;

bool argcmp(const Point &a, const Point &b)
{
    auto quad = [](const Point &a)
    {
        if (a.y < -eps) return 1;
        if (a.y > eps) return 4;
        if (a.x < -eps) return 5;
        if (a.x > eps) return 3;
        return 2;
    };
    int qa = quad(a), qb = quad(b);
    if (qa != qb) return qa < qb;
    auto t = a ^ b;
    //if (abs(t) <= eps) return a * a < b * b - eps;
    return t > eps;
}

pair<_T, _T> minmax_triangle(const vector<Point> &vec)
{
    if (vec.size() <= 2) return {0, 0};
    vector<pair<int, int>> evt;
    evt.reserve(vec.size() * vec.size());
    const _T t = abs((vec[0] - vec[1]) ^ (vec[0] - vec[2]));
    _T maxans = t, minans = t;
    for (size_t i = 0; i < vec.size(); i ++ )
    {
        for (size_t j = 0; j < vec.size(); j ++ )
        {
            if (i == j || vec[i] == vec[j]) continue;
            evt.push_back({i, j});
        }
    }
    sort(evt.begin(), evt.end(), [&](const pair<int, int> &u, const pair<int, int> &v)
    {
        const Point du = vec[u.second] - vec[u.first], dv = vec[v.second] - vec[v.first];
        return argcmp({du.y,-du.x}, {dv.y,-dv.x}); 
    });

    vector<size_t> vx(vec.size()), pos(vec.size());
    for (size_t i = 0; i < vec.size(); i ++ ) vx[i] = i;
    sort(vx.begin(), vx.end(), [&](int x, int y) { return vec[x] < vec[y]; });
    for (size_t i = 0; i < vx.size(); i++) pos[vx[i]] = i;
    for (auto [u, v] : evt)
    {
    	//printf("%d %d-\n",u,v);
        size_t i = pos[u], j = pos[v];
        if (i > j) swap(u, v), swap(i, j);
        const Point vecu = vec[u], vecv = vec[v];
        if (i > 0) minans = min(minans, abs((vec[vx[i - 1]] - vecu) ^ (vec[vx[i - 1]] - vecv)));
        if (j < vx.size() - 1) minans = min(minans, abs((vec[vx[j + 1]] - vecu) ^ (vec[vx[j + 1]] - vecv)));
        maxans = max({maxans, abs((vec[vx[0]] - vecu) ^ (vec[vx[0]] - vecv)), abs((vec[vx.back()] - vecu) ^ (vec[vx.back()] - vecv))});
        swap(vx[i], vx[j]);
        pos[u] = j;
        pos[v] = i;
    }
    return {minans, maxans};
}

signed main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    int n;
    cin >> n;

    vector<int> a(n), b(n);
    vector<Point> vec(n);
    for(int i = 0; i < n; i ++ ) cin >> a[i];
    for(int i = 0; i < n; i ++ ) cin >> b[i];
    for(int i = 0; i < n; i ++ ) vec[i] = {a[i], b[i]};

    auto ans = minmax_triangle(vec);

    cout << ans.first << '\n' << ans.second << '\n';

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值