[M贪心] lcLCP30. 魔塔游戏(STL优先队列+堆+贪心)

Posted Ypuyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[M贪心] lcLCP30. 魔塔游戏(STL优先队列+堆+贪心)相关的知识,希望对你有一定的参考价值。

1. 题目来源

链接:LCP 30. 魔塔游戏

2. 题目解析

挺不错的一道贪心问题。

思路:

  • 首先顺序累加所有怪物血量,在血量初始值为 1 时,若累加完毕, s u m ≤ 0 sum \\le0 sum0 则说明怎么调整也是无法保证走完所有房间且血量符合要求的。返回 -1 即可。反之,一定可以通过调整走完所有房间,大不了就将所有的负数全部放到最后,就可以了。
  • 但是如何保证调整次数最少呢?一定不能见到一个负数就操作一次吧。
  • 贪心调整思路如下:
    • 每次在我们血量 b l o o d ≤ 0 blood \\le 0 blood0 的时我们进行调整。调整时,将之前我们遇到的对我们伤害最大的怪物放到最后。即负数最小的,也就是负数中绝对值最大的怪物放到最后。因为之前遇到过,血量已经被他扣了,在调整时,要将之前被这个怪物扣的血量补充回来。直到依次将扣血最大的怪物向后调整,补充血量到 > 0 \\gt0 >0 后,再依次向后走。
    • 血量初始为 1 ,为题目要求。顺序遍历怪物,记录遇到的负血量的怪物,由于需要动态的记录这些负血量怪物的最大值,所以需要使用优先队列。
    • 每遇到一个怪物,不论血量正负,都和当前的血量 b l o o d blood blood 进行累加。且记录负血量怪物进小顶堆,在此使用技巧,负值可以添加负号变为正值,然后放入大顶堆,达到和小顶堆同样的效果。注意出堆时,需要再补充回一个负号。
    • b l o o d ≤ 0 blood\\le0 blood0 时,一定是之前遇到了负血量怪物,那么就要将堆中这些负血量怪物,按照扣出血量大小依次出堆,补充给 b l o o d blood blood,直到将 b l o o d blood blood 补充回 > 0 \\gt0 >0 的状态。然后就不必再调整了。
    • 在此,直接取堆顶元素补充给血量即可,然后直接将堆顶元素出堆,不需要再保留该怪物的血量作记录。因为一定可以经过调整遍历完所有怪物房间,且只会有负血量怪物调整到末尾。所以,我们在血量见底时,假装的没遍历,调整后血量补充,等价于跳过这个扣血最大的怪物,将其放到最后。那么,遍历完之后我们剩余的血量 b l o o d blood blood,也是一定可以将最后这些调整的连续负血量怪物遍历完的。最后只需要返回最小的调整次数即可,剩余血量,就是一开始累加的 s u m sum sum

总结如下:

  • 一开始累加所有怪物血量,若 ≤ 0 \\le0 0,则返回 -1,无法调整。
  • 反之,一定可以调整。顺序遍历所有怪物,累加血量 b l o o d blood blood,并将负血量怪物记录进优先队列,用以动态计算扣血最大的负血量怪物。当血量 b l o o d ≤ 0 blood\\le0 blood0,则从堆中依次弹出之前遇到的扣血最大的怪物用以回血。这样一来,之前扣的血,现在再加上,等价于没遍历这个怪物,等价于将其调整到最后,则调整次数 +1。
  • 当遍历到数组末尾时,该末尾后面全是调整过来的负血量怪物,已经不需在此调整。一定保证当前剩余血量可以遍历完这些连续的负血量怪物,故直接返回调整次数即可。

注意开 LL


  • 时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
  • 空间复杂度 O ( n ) O(n) O(n)

代码:

class Solution {
public:
    int magicTower(vector<int>& nums) {
        typedef long long LL;
        
        LL sum = 1;
        for (int x : nums) sum += x;
        if (sum <= 0) return -1;
        
        LL blood = 1, res = 0;
        priority_queue<int> q;
        for (int x : nums) {
            if (x < 0) q.push(-x);
            blood += x;
            while (blood <= 0) {
                blood += q.top(); q.pop();
                res ++ ;
            }
        }

        return res;
    }
};

以上是关于[M贪心] lcLCP30. 魔塔游戏(STL优先队列+堆+贪心)的主要内容,如果未能解决你的问题,请参考以下文章

[M贪心] lc1353. 最多可以参加的会议数目(扫描线+STL优先队列)

数列极差问题-STL优先队列-贪心

“盛大游戏杯”第15届上海大学程序设计联赛夏季赛暨上海高校金马五校赛题解&&源码A,水,B,水,C,水,D,快速幂,E,优先队列,F,暴力,G,贪心+排序,H,STL乱搞,I,尼姆博(

C课程设计——魔塔游戏

分享四款怀旧小游戏魔塔+伏魔记+三国霸业+寻仙纪

bzoj2130: 魔塔