You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

矩形分区选Top-K最大区域代码优化:解决超时问题

矩形区域Top-K面积优化问题

问题背景

我正在解决一个问题:将尺寸为w x h的矩形王国通过垂直和水平线条划分为多个区域,任务是选出k个面积最大的区域,并计算其中最大与最小面积的差值。

任务详情

2024年,T王国的奥列格国王迎来60岁生日,他关注遗产分配问题。当前T王国是w × h的矩形,被平行于边的线条划分为区域,垂直切割点坐标为x1, x2...xn,水平切割点坐标为y1, y2...ym。
例如,当w = 10, h = 8, x = [1, 5, 7], y = [4, 6]时,王国划分如截图所示。奥列格有k个儿子,他要给每个儿子分配一个区域,剩余区域由精英管理。他希望给儿子们分配k个面积最大的区域,长子得最大的,幼子得这k个里最小的,需要计算这两个区域的面积。

当前问题

代码通过了100个测试用例中的97个,但在第98个测试用例出现**运行时间超限(2秒)**的错误。

我的疑问

如何优化该算法以减少运行时间?能否避免双重循环或更高效地找出Top-K面积的区域?

当前代码

#include <iostream>
#include <vector>
#include <queue>
#include <tuple>
#include <algorithm>
#include <climits>
#include <memory_resource>

struct compare {
    bool operator()(const std::tuple<long long, int, int>& a, const std::tuple<long long, int, int>& b) {
        return std::get<0>(a) < std::get<0>(b);
    }
};

int main() {
    long long w, h;
    std::cin >> w >> h;
    int n, m, k;
    std::cin >> n >> m >> k;

    std::vector<long long> x(n + 2), y(m + 2);
    x[0] = 0; x[n + 1] = w;
    y[0] = 0; y[m + 1] = h;

    for (int i = 1; i <= n; i++) std::cin >> x[i];
    for (int i = 1; i <= m; i++) std::cin >> y[i];

    std::vector<long long> widths(n + 1), heights(m + 1);
    for (int i = 1; i <= n + 1; i++) widths[i - 1] = x[i] - x[i - 1];
    for (int i = 1; i <= m + 1; i++) heights[i - 1] = y[i] - y[i - 1];

    if (widths.size() > k) {
        std::nth_element(widths.begin(), widths.begin() + k - 1, widths.end(), std::greater{});
        widths.resize(k);
    }
    if (heights.size() > k) {
        std::nth_element(heights.begin(), heights.begin() + k - 1, heights.end(), std::greater{});
        heights.resize(k);
    }

    std::sort(widths.begin(), widths.end(), std::greater{});
    std::sort(heights.begin(), heights.end(), std::greater{});

    std::pmr::unsynchronized_pool_resource pool;
    using queue_container_t = std::pmr::vector<std::tuple<long long, int, int>>;
    std::priority_queue<std::tuple<long long, int, int>, queue_container_t, compare> maxHeap{ std::pmr::polymorphic_allocator<queue_container_t>{&pool} };

    maxHeap.emplace(widths[0] * heights[0], 0, 0);

    std::vector<std::vector<bool>> visited(n + 1, std::vector<bool>(m + 1, false));
    visited[0][0] = true;

    long long smallest = LLONG_MAX, largest = LLONG_MIN;

    for (int count = 0; count < k; ++count) {
        auto [area, i, j] = maxHeap.top();
        maxHeap.pop();

        smallest = std::min(smallest, area);
        largest = std::max(largest, area);

        if (i + 1 < widths.size() && !visited[i + 1][j]) {
            maxHeap.emplace(widths[i + 1] * heights[j], i + 1, j);
            visited[i + 1][j] = true;
        }
        if (j + 1 < heights.size() && !visited[i][j + 1]) {
            maxHeap.emplace(widths[i] * heights[j + 1], i, j + 1);
            visited[i][j + 1] = true;
        }
    }

    std::cout << smallest << " " << largest << std::endl;
    return 0;
}

输入输出示例

输入输出
10 8
3 2
6
1 5 7
4 6
6 16

优化建议

1. 移除不必要的PMR内存池

当前代码使用std::pmr内存池,实际高频操作中反而会增加内存管理开销。直接使用默认的std::priority_queue(基于std::vector)即可,减少复杂度。

2. 缩小visited数组的空间

原visited数组大小为(n+1)x(m+1),但经过nth_element和resize后,widths和heights的最大长度都是k,因此visited只需k x k的大小,大幅减少内存占用和初始化时间。

3. 替换visited的实现为哈希集合

二维数组的访问可能存在缓存不友好问题,可将(i,j)编码为64位整数(例如static_cast<uint64_t>(i) << 32 | j),用std::unordered_set<uint64_t>记录已访问的坐标,提升访问速度。

4. 去掉冗余的排序步骤

std::nth_element已经保证前k个元素是最大的k个,后续的sort完全多余,可直接删除,节省O(k log k)的时间。修改后的宽度高度处理:

if (widths.size() > k) {
    std::nth_element(widths.begin(), widths.begin() + k - 1, widths.end(), std::greater{});
    widths.resize(k);
}
if (heights.size() > k) {
    std::nth_element(heights.begin(), heights.begin() + k - 1, heights.end(), std::greater{});
    heights.resize(k);
}

5. 用结构体替代tuple提升访问效率

std::tuple的元素访问比结构体成员慢,可定义简单结构体存储数据:

struct AreaNode {
    long long area;
    int i;
    int j;
    AreaNode(long long a, int x, int y) : area(a), i(x), j(y) {}
    bool operator<(const AreaNode& other) const {
        return area < other.area;
    }
};

之后使用std::priority_queue<AreaNode>,减少模板开销,提升访问速度。

6. 确保切割点有序

如果输入的切割点坐标无序,需先对x、y数组排序,否则计算的宽度高度会出错,间接影响性能:

std::sort(x.begin() + 1, x.end() - 1);
std::sort(y.begin() + 1, y.end() - 1);

内容的提问来源于stack exchange,提问作者Rocowoco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 15:09:49