[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;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
校园失物招领系统管理系统按照操作主体分为管理员和用户。管理员的功能包括字典管理、论坛管理、公告信息管理、失物招领管理、失物认领管理、寻物启示管理、寻物认领管理、用户管理、管理员管理。用户的功能等。该系统采用了Mysql数据库,Java语言,Spring Boot框架等技术进行编程实现。 校园失物招领系统管理系统可以提高校园失物招领系统信息管理问题的解决效率,优化校园失物招领系统信息处理流程,保证校园失物招领系统信息数据的安全,它是一个非常可靠,非常安全的应用程序。 ,管理员权限操作的功能包括管理公告,管理校园失物招领系统信息,包括失物招领管理,培训管理,寻物启事管理,薪资管理等,可以管理公告。 失物招领管理界面,管理员在失物招领管理界面中可以对界面中显示,可以对失物招领信息的失物招领状态进行查看,可以添加新的失物招领信息等。寻物启事管理界面,管理员在寻物启事管理界面中查看寻物启事种类信息,寻物启事描述信息,新增寻物启事信息等。公告管理界面,管理员在公告管理界面中新增公告,可以删除公告。公告类型管理界面,管理员在公告类型管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值