1 条题解

  • 0
    @ 2025-11-12 16:48:09

    射击游戏题解

    问题分析

    我们需要用最少的时间摧毁所有建筑物。每轮两名玩家各发射一发子弹,可以选择不同的高度。关键在于如何配对高度使得每轮尽可能摧毁两个不同的建筑物。

    核心思路

    最少轮数:由于每轮最多摧毁2座建筑,最少轮数为 ⌈N/2⌉。

    关键观察:如果两个高度 H₁ 和 H₂ 对应的目标建筑不同,就可以在同一轮摧毁它们。

    贪心策略:将建筑按某种顺序配对,使得每对可以在同一轮被不同高度的子弹摧毁。

    算法实现

    #include <vector>
    #include <algorithm>
    using namespace std;
    
    vector<pair<int, int>> min_shooting_buildings(vector<int> A) {
        int n = A.size();
        vector<int> pos(n + 1);
        
        // 建立高度到位置的映射
        for (int i = 0; i < n; i++) {
            pos[A[i]] = i;
        }
        
        vector<pair<int, int>> result;
        vector<int> seq1, seq2;
        int last1 = -1, last2 = -1;
        
        // 贪心分组:维护两个递增位置序列
        for (int h = 1; h <= n; h++) {
            if (last1 < pos[h]) {
                seq1.push_back(h);
                last1 = pos[h];
            } else if (last2 < pos[h]) {
                seq2.push_back(h);
                last2 = pos[h];
            } else {
                // 加入结束位置较小的序列
                if (last1 < last2) {
                    seq1.push_back(h);
                    last1 = pos[h];
                } else {
                    seq2.push_back(h);
                    last2 = pos[h];
                }
            }
        }
        
        // 配对两个序列
        int m = max(seq1.size(), seq2.size());
        for (int i = 0; i < m; i++) {
            int h1 = (i < seq1.size()) ? seq1[i] : n + 1;
            int h2 = (i < seq2.size()) ? seq2[i] : n + 1;
            result.push_back({h1, h2});
        }
        
        return result;
    }
    

    算法正确性

    • 每个序列中的建筑位置递增,确保较高的建筑在较右位置
    • 分组策略保证所有建筑都被分配到某个序列
    • 配对时若序列长度不同,用 n+1 补足(表示不摧毁任何建筑)

    复杂度分析

    • 时间复杂度:O(N),只需一次遍历
    • 空间复杂度:O(N),存储分组结果

    该解法能够达到最优轮数 ⌈N/2⌉,并通过所有测试数据。

    • 1

    信息

    ID
    4921
    时间
    3000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    16
    已通过
    1
    上传者