最大点问题

这是一个经典的二维“最大点”或“支配关系”问题,下面是完整的解答:


a. 算法设计与分析

问题回顾(更直白):

一个点 ( x i , y i ) (x_i, y_i) (xi,yi) 被支配,是指存在另一个点 ( x j , y j ) (x_j, y_j) (xj,yj),满足:

  • x i ≤ x j x_i \le x_j xixj y i ≤ y j y_i \le y_j yiyj
  • 且至少有一个方向是严格小于的(否则是同一个点)

我们要找出 所有不被支配的点,即最大点集合(Maximal Points)


✅ 算法思路(排序 + 扫描):

  1. 按 x 坐标降序排序

    • 如果 x 相同,按 y 升序;
  2. 从左往右扫描每个点,维护一个变量 max_y_so_far

  3. 如果当前点的 y 大于 max_y_so_far,就说明它不是被别人支配的最大点;

  4. 更新 max_y_so_far


示例代码(C++):

#include 
#include 
#include 
using namespace std;

struct Point {
    int x, y;
};

bool compare(const Point& a, const Point& b) {
    // 按 x 降序排列;若 x 相同,按 y 升序排列
    return a.x > b.x || (a.x == b.x && a.y < b.y);
}

vector<Point> findMaximalPoints(vector<Point>& points) {
    sort(points.begin(), points.end(), compare);

    vector<Point> result;
    int max_y_so_far = INT_MIN;

    for (const auto& p : points) {
        if (p.y > max_y_so_far) {
            result.push_back(p);
            max_y_so_far = p.y;
        }
    }

    return result;
}

⏱️ 时间复杂度分析:

步骤 时间复杂度
排序 O ( n log ⁡ n ) O(n \log n) O(nlogn)
扫描 O ( n ) O(n) O(n)
总计 O ( n log ⁡ n ) O(n \log n) O(nlogn)

b. 现实生活中的应用场景:

这个“最大点”问题又叫二维天空线问题(Skyline problem),在以下场景中很常见:

✅ 现实实例:

  1. 产品优选筛选

    • 比如在选择笔记本电脑:价格低、性能高的机器 → 最大点。
    • 每台电脑有两个参数(价格,性能),找到不被其他产品支配的产品。
  2. 房地产分析

    • 每个房子是一个点(面积,价格),寻找在“面积更大而价格不高”的最佳房子集合。
  3. 数据库多维查询优化

    • SQL 查询中找出“多属性非支配记录”,如航班选择:耗时短、价格低。
  4. 投资组合选择

    • 每个股票/基金:收益和风险两维度 → 找到最优投资点。
  5. 就业择业建议系统

    • 岗位的薪资与工作强度作为两个维度,找出不被支配的工作岗位。

例:

{(1,3), (2,2), (3,1), (4,4), (5,0)}

(5, 0)是不是最大点呢?

是的,在严格按照定义的支配关系下,(5,0) 也确实是最大点,因为:

  • 没有其他点横坐标 ≥ 5;
  • 所以没人能支配它;
  • 虽然它的 y 很小,但没人比它在 x 上更“右”,所以它不被支配。

核心理解:

最大点不一定“好看”或“数值最大”;
它只是“不被别人同时在 x 和 y 上都更优”:

  • (4, 4):左上角高端点,不被任何点支配 ✅
  • (5, 0):最右端,没人 x ≥ 5,没人支配它 ✅

好的!我们现在来扩展到三维空间,即处理点集合 ( x , y , z ) (x, y, z) (x,y,z),并找出所有不被其他点支配的最大点


三维

三维“最大点”定义(支配关系):

在三维中,点 A = ( x 1 , y 1 , z 1 ) A = (x_1, y_1, z_1) A=(x1,y1,z1) 支配点 B = ( x 2 , y 2 , z 2 ) B = (x_2, y_2, z_2) B=(x2,y2,z2),当且仅当:

  • x 1 ≥ x 2 x_1 \ge x_2 x1x2
  • y 1 ≥ y 2 y_1 \ge y_2 y1y2
  • z 1 ≥ z 2 z_1 \ge z_2 z1z2
  • 至少一个维度是严格大于

我们要找出所有不被其他点支配的最大点。


✅ 算法概述(暴力但清晰):

由于三维不再能像二维那样用排序+扫描处理,我们用:

  • 暴力判断每个点是否被支配(O(n²))
  • 对每对点比较,判断支配关系

这适合中等规模(例如 n ≤ 1 0 4 n \leq 10^4 n104)。


完整 C++ 实现(支持三维最大点):

#include 
#include 
using namespace std;

struct Point3D {
    int x, y, z;

    void print() const {
        cout << "(" << x << ", " << y << ", " << z << ")";
    }
};

// 判断 A 是否支配 B
bool dominates(const Point3D& A, const Point3D& B) {
    bool strictly_greater = false;
    if (A.x < B.x || A.y < B.y || A.z < B.z)
        return false;
    if (A.x > B.x) strictly_greater = true;
    if (A.y > B.y) strictly_greater = true;
    if (A.z > B.z) strictly_greater = true;
    return strictly_greater;
}

vector<Point3D> findMaximalPoints3D(const vector<Point3D>& points) {
    int n = points.size();
    vector<bool> is_dominated(n, false);

    for (int i = 0; i < n; ++i) {
        if (is_dominated[i]) continue;
        for (int j = 0; j < n; ++j) {
            if (i == j) continue;
            if (dominates(points[j], points[i])) {
                is_dominated[i] = true;
                break;
            }
        }
    }

    vector<Point3D> result;
    for (int i = 0; i < n; ++i) {
        if (!is_dominated[i])
            result.push_back(points[i]);
    }

    return result;
}

int main() {
    vector<Point3D> points = {
        {1, 2, 3}, {3, 2, 1}, {2, 3, 1}, {4, 4, 4}, {5, 0, 0}, {0, 5, 0}, {0, 0, 5}
    };

    vector<Point3D> maximal = findMaximalPoints3D(points);

    cout << "三维最大点(不被支配的点)有:" << endl;
    for (const auto& p : maximal) {
        p.print();
        cout << endl;
    }

    return 0;
}

✅ 输出示例(基于上面样例):

三维最大点(不被支配的点)有:
(4, 4, 4)
(5, 0, 0)
(0, 5, 0)
(0, 0, 5)

这些点都没有在 x、y、z 三维中被其他点“更大等”且至少一维更大的点支配。


算法复杂度

  • 时间复杂度 O ( n 2 ) O(n^2) O(n2)
  • 空间复杂度 O ( n ) O(n) O(n)
  • 若数据量特别大(如 >10^5),可用三维数据结构或分治策略优化(如 kd-tree、Divide and Conquer)

你可能感兴趣的:(算法)