蓝桥杯 第 2 场算法双周赛 第4题 通关【算法赛】c++ 优先队列 + 小根堆 详解注释版

news2024/9/23 15:24:32

 题目

通关【算法赛】icon-default.png?t=N7T8https://www.lanqiao.cn/problems/5889/learning/?contest_id=145

问题描述

小蓝最近迷上了一款电玩游戏“蓝桥争霸”。这款游戏由很多关卡和副本组成,每一关可以抽象为一个节点,整个游戏的关卡可以抽象为一棵树形图,每一关会有一道算法题,只有当经验值不低于第 i 关的要求 ki​ 时,小蓝才能挑战成功通过此关,并且获得 si​ 的经验值,每关的经验值只能获得一次。每个关卡(除了 11 号点),都会有一个前置关卡,只有通过了前置关卡,才能挑战后续关卡。

小蓝初始在 11 号点,也就是游戏开局初始点,同时具有一个初始经验值 P,他可以任意规划挑战顺序,他想问你最多能够挑战成功多少道题。

小蓝会告诉你关卡的所有信息,以及他的初始经验值,你需要回答他最多能够挑战成功多少关卡。

输入格式

第一行输入两个整数 n,P,表示关卡的数量以及小蓝的初始经验值。

接下来 n 行,每行输入三个整数 fi​,si​,ki​,fi​ 表示每一关的前置关卡( f1​ 一定为 00 ),si​ 表示经验值,ki​ 表示挑战成功最少需要的经验值。

输出格式

一个整数,表示在最优的规划下,最多能挑战成功的关卡数量。

样例输入

4 5
0 3 5
1 2 8
1 3 9
3 1 15

样例输出

3

说明

游戏地图如下:

关卡描述

小蓝初始点在 11 号关卡,初始经验为 55。每个关卡具有挑战前提:11 号关卡可以直接挑战,如果要挑战 22 号关卡,必须通过 11 号关卡,3,43,4号关卡类似。

小蓝的一种挑战顺序如下:

  1. 由于初始经验为 55,满足 11 号关卡要求,所以可以直接挑战成功 11 号关卡,获得 33 经验值,此时经验值为 88,并且获得挑战 2,32,3 号关卡的机会。

  2. 此时经验为 88,满足 22 号关卡要求,但是不满足 33 号要求,所以可以直接挑战成功 22 号关卡,获得 22 经验值,此时经验值为 1010。

  3. 此时经验为 1010,满足 33 号关卡要求,所以对 33 号关卡挑战成功,获得 33 经验值,此时经验值为 1313,并且获得挑战 44 号关卡的机会。

  4. 此时经验为 1313,小于 44 号关卡要求,所以无法成功挑战 44 号关卡,游戏无法继续。

评测数据范围

f1​=0<fi​≤n≤105,0≤P,si​,ki​≤109。

数据保证输入为一棵树,并且根节点为 11。

运行限制

语言最大运行时间最大运行内存
C++1s256M
C1s256M
Java2s256M
Python33s256M
PyPy33s256M

思路和解题方法

首先,定义了一些全局变量和类型别名:

  • N 定义为 1e5+100,表示任务数量的上限。
  • Pair 是一个包含两个整数的类型别名,用于存储任务的优先级和任务编号。
  • G 是一个邻接表,用于存储任务关系图,每个任务的子任务列表存储在 G 中。
  • S 数组用于存储每个任务的耗能值。
  • K 数组用于存储每个任务的优先级。
  • n 表示任务数量。
  • P 表示初始能量值。
  • cntvis 是辅助变量。

接下来是 sol 函数,用于解决任务调度问题。函数的主要逻辑如下:

  1. 读取任务数量 n 和初始能量值 P
  2. 使用循环读取每个任务的父任务编号 f、耗能值 S[i] 和优先级 K[i],并将每个任务添加到对应父任务的子任务列表中。
  3. 创建一个最小堆(优先队列) q,用于存储任务的优先级和任务编号,按照优先级从小到大排序。
  4. 将初始任务(编号为0)的优先级和编号加入队列。
  5. 初始化完成任务的计数器 ccnt 为 -1,因为初始任务不计入完成数量。
  6. 进入循环,当队列不为空时进行以下操作:
    • 检查当前能量值是否大于等于队首任务的优先级。
    • 如果满足条件,表示能够执行任务:
      • 完成任务数量 ccnt 加一。
      • 取出队首任务,并将其从队列中弹出。
      • 将任务的能量值加到当前能量值上。
      • 遍历该任务的子任务,将子任务的优先级和编号加入队列。
    • 如果当前能量值不足以执行队首任务,跳出循环。
  7. 输出完成任务的数量 ccnt

        使用了优先队列(最小堆)来实现任务调度。通过不断执行优先级最高的任务,并更新能量值,直到能量值不足以执行下一个任务为止。最终输出完成的任务数量。

复杂度

        时间复杂度:

                O(n^2)

时间复杂度:

  • 读取任务数量和初始能量值的时间复杂度为 O(1)。
  • 循环读取每个任务的父任务编号、耗能值和优先级的时间复杂度为 O(n)。
  • 创建优先队列 q 的时间复杂度为 O(nlogn),其中 n 是任务数量。
  • 循环执行任务的时间复杂度取决于任务的数量和任务之间的关系。在最坏情况下,每个任务都是其他任务的子任务,因此循环执行任务的时间复杂度为 O(n^2)。但是,如果任务之间的关系是稀疏的,循环执行任务的时间复杂度可能会小于 O(n^2)。
  • 输出完成任务数量的时间复杂度为 O(1)。

总结,整个算法的时间复杂度在最坏情况下为 O(n^2),但在实际情况下可能会更好。

        空间复杂度:

                O(n)

空间复杂度:

  • 邻接表 G 的空间复杂度为 O(n),存储了任务之间的关系。
  • 数组 S 和 K 的空间复杂度为 O(n),存储了每个任务的耗能值和优先级。
  • 优先队列 q 的空间复杂度为 O(n),存储了任务的优先级和任务编号。
  • 辅助变量的空间复杂度可以忽略不计。

总结,整个算法的空间复杂度为 O(n),其中 n 是任务数量。

c++ 代码

#include <iostream>
#include <vector>
#include <queue> // 包含优先队列的头文件
using namespace std;

const int N = 1e5 + 100; // 定义任务数量的上限

typedef pair<int, int> Pair; // 定义一个包含两个整数的类型别名
vector<int> G[N]; // 邻接表,存储任务之间的关系
int S[N], K[N]; // 数组,存储每个任务的耗能值和优先级
int n, P, cnt, vis[N]; // 全局变量,表示任务数量、初始能量值、辅助变量

void sol() {
    cin >> n >> P; // 读取任务数量和初始能量值

    for (int i = 1; i <= n; i++) {
        int f;
        cin >> f >> S[i] >> K[i]; // 读取父任务编号、耗能值和优先级
        G[f].push_back(i); // 将当前任务加入对应父任务的子任务列表中
    }

    priority_queue<Pair, vector<Pair>, greater<Pair>> q; // 创建一个最小堆,用于存储任务的优先级和任务编号
    q.push({K[0], 0}); // 将初始任务加入队列中

    int ccnt = -1; // 完成任务的计数器,初始值为 -1,因为初始任务不计入完成数量

    while (!q.empty()) { // 当队列不为空时,循环执行任务
        auto [k, u] = q.top(); // 取出队首任务的优先级和编号
        q.pop(); // 将队首任务从队列中弹出

        if (P >= k) { // 如果当前能量值可以执行队首任务
            P += S[u]; // 将任务的能量值加到当前能量值上
            ccnt++; // 完成任务数量加一

            for (auto v : G[u]) { // 遍历该任务的子任务
                q.push({K[v], v}); // 将子任务的优先级和编号加入队列
            }
        } else { // 如果当前能量值不足以执行队首任务
            break; // 跳出循环
        }
    }

    cout << ccnt << endl; // 输出完成任务的数量
}

int main() {
    sol(); // 调用 sol 函数解决问题
    exit(0); // 终止程序
}

相关知识 和推荐视频

1. pair:  Pair 基础

  • pair 是 C++ 标准库中的一个模板类,用于存储两个值的有序对。它定义在 <utility> 头文件中。
  • pair 类模板接受两个类型参数,分别表示第一个值的类型和第二个值的类型。例如,pair<int, double> 表示一个包含一个整数和一个浮点数的有序对。
  • pair 类模板的实例可以通过花括号 {} 初始化,也可以通过构造函数进行初始化。可以使用 firstsecond 成员变量来访问有序对中的第一个值和第二个值。

2. 优先队列   小顶堆  堆 的介绍 建议选着来看,看看大小堆是啥有啥用,就行了。 

建议跳看

 priority_queue<Pair, vector<Pair>, greater<Pair>> q;
  • priority_queue 是 C++ 标准库中的一个模板类,用于实现优先队列(堆)。它定义在 <queue> 头文件中。
  • priority_queue 类模板接受三个类型参数,分别表示存储在队列中的元素类型、底层容器类型和比较函数对象类型。例如,priority_queue<int, vector<int>, greater<int>> 表示一个存储整数的优先队列,使用 vector 作为底层容器,并按照从小到大的顺序进行排序。
  • 在代码中,Pair 是一个包含两个整数的类型别名,vector<Pair> 表示使用 vector 作为底层容器来存储 Pair 类型的元素,greater<Pair> 表示使用 greater 函数对象来定义元素之间的比较关系。
  • greater<Pair> 是一个函数对象,它定义了对 Pair 类型的元素进行比较的方式。在这里,greater<Pair> 使用 operator() 函数重载来比较两个 Pair 类型的元素,根据 Pair 中第一个值的大小进行比较。因此,priority_queue<Pair, vector<Pair>, greater<Pair>> 创建的优先队列会按照 Pair 中第一个值的从小到大的顺序进行排序。

3.扩展

大顶堆

大顶堆可以通过使用 less 函数对象来定义元素之间的比较关系。

在 C++ 中,priority_queue 默认使用 less 函数对象来实现大顶堆。

4.再解释一下内容

while (!q.empty()) {
        if (P >= q.top().first) { // 当当前能量值大于等于队首任务的优先级时,执行任务
            ccnt ++; // 完成任务数量加一
            Pair tmp = q.top(); // 取出队首任务
            q.pop(); // 弹出队首任务
            P += S[tmp.second]; // 将任务的能量值加到当前能量值上
            for (int v : G[tmp.second]) { // 遍历该任务的子任务
                q.push({K[v], v}); // 将子任务的优先级和编号加入队列
            }
        } else {
            break; // 当前能量值不足以执行队首任务时,跳出循环
        }
    }
  1. while (!q.empty()):当任务队列不为空时,执行循环体内的代码。

  2. if (P >= q.top().first):判断当前能量值 P 是否大于等于队首任务的优先级 q.top().first。如果是,则执行任务;否则,跳出循环。

  3. ccnt++:完成任务数量加一。

  4. Pair tmp = q.top():取出队首任务,并将其存储在临时变量 tmp 中。

  5. q.pop():弹出队首任务,将其移出任务队列。

  6. P += S[tmp.second]:将任务的能量值 S[tmp.second] 加到当前能量值 P 上,表示执行任务消耗了一定的能量。

  7. for (int v : G[tmp.second]):遍历该任务的子任务,使用范围-based for 循环,将每个子任务的编号存储在变量 v 中。

  8. q.push({K[v], v}):将子任务的优先级 K[v] 和编号 v 加入任务队列 q 中,表示将子任务加入待执行的任务队列中。

  9. else:当当前能量值不足以执行队首任务时,跳出循环。

觉得有用的话可以点点赞,支持一下。

如果愿意的话关注一下。会对你有更多的帮助。

每天都会不定时更新哦  >人<  。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1143715.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

asp.net教务管理信息系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio计算机毕业设计

一、源码特点 asp.net 教务管理信息系统是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语言 开发 asp.net教务管理系统 应用技术&a…

基于SSM的高校图书馆设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

真机环境配置教程

1.下载安装包 https://developers.google.com/android/images 2.刷机教程 Xposed精品连载 | 一篇文章彻底搞定安卓刷机与Root 3.配置root

【VTK】关于VTK图像的系列功能

很高兴在雪易的CSDN遇见你 &#xff0c;给你糖糖 欢迎大家加入雪易社区-CSDN社区云 前言 本文总结VTK中图像的系列功能&#xff0c;包括图像的导入&#xff08;读取&#xff09;、显示、交互和导出&#xff08;保存&#xff09;等。详细讲解VTK中提供的各种解决思路&#xff…

DreamTexture.js - 基于稳定扩散的3D模型自动纹理化开发包

DreamTexture.js 是面向 three.js 开发者的 3D 模型纹理自动生成与设置开发包&#xff0c;可以为 webGL 应用增加 3D 模型的快速自动纹理化能力&#xff0c;官方下载地址&#xff1a;DreamTexture.js自动纹理化开发包 。 图一为原始模型, 图二图三为贴图后的模型。提示词&#…

PN8370 超低待机功耗准谐振原边反馈交直流转换器 适用于5V 2A的充电器芯片

PN8370集成超低待机功耗准谐振原边控制器及650V高雪崩能力智能功率MOSFET&#xff0c;用于高性能、外围元器件精简的充电器、适配器和内置电源。 PN8370为原边反馈工作模式,可省略光耦和TL431。内置高压启动电路,可实现芯片空载损耗(230VAC)小于30mW。在恒压模式&#xff0c;采…

FindDiff_Qt找不同项目

文章目录 项目简介源代码widget.hwidget.cppwidget.ui配置文件找不同.json 项目简介 开发平台 win10Qt6.6msvc2022 简介 微信上有一些好玩的游戏, 找不同一种比较轻松有趣的游戏,也曾经在街机上被坑过N币, 玩了几次后,发现还是太难了,于是开始截屏放大,慢慢找,再然后就发展到截…

2023软件测试高频面试题

前言 今天&#xff0c;我们来整理与解析一些比较高频的测试行业面试题&#xff0c;大家可以通过面试题内的一些解析&#xff0c;再结合自己的真实工作经验来进行答题思路的提取、整理。 友情提示&#xff1a;硬背答案虽可&#xff0c;但容易翻车哦。 同时&#xff0c;我也准备…

【蓝桥杯选拔赛真题04】C++计算24数字游戏 青少年组蓝桥杯C++选拔赛真题 STEMA比赛真题解析

目录 C/C++计算24数字游戏 一、题目要求 1、编程实现 2、输入输出 二、算法分析

7、电路综合-基于简化实频的SRFT微带线巴特沃兹低通滤波器设计

7、电路综合-基于简化实频的SRFT微带线巴特沃兹低通滤波器设计 5、电路综合-超酷-基于S11参数直接综合出微带线电路图中已经介绍了如何从传输函数或S参数综合出电路图。 24、基于原型的切比雪夫低通滤波器设计理论&#xff08;插入损耗法&#xff09;中介绍了使用集总参数元件…

基于SSM的航班订票管理系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

【Python · PyTorch】线性代数 微积分

本文采用Python及PyTorch版本如下&#xff1a; Python&#xff1a;3.9.0 PyTorch&#xff1a;2.0.1cpu 本文为博主自用知识点提纲&#xff0c;无过于具体介绍&#xff0c;详细内容请参考其他文章。 线性代数 & 微积分 1. 线性代数1.1 基础1.1.1 标量1.1.2 向量长度&…

PyTorch中grid_sample的使用方法

官方文档首先Pytorch中grid_sample函数的接口声明如下&#xff1a; torch.nn.functional.grid_sample(input, grid, modebilinear, padding_modezeros, align_cornersNone)input : 输入tensor&#xff0c; shape为 [N, C, H_in, W_in]grid: 一个field flow&#xff0c; shape为…

PS 安装教程 2022版(全网最详细图文教程)

目录 一.简介 二.安装步骤 软件&#xff1a;PS版本&#xff1a;2022语言&#xff1a;简体中文大小&#xff1a;2.83G安装环境&#xff1a;Win10&#xff08;1903&#xff09;及以上版本&#xff0c;64位操作系统硬件要求&#xff1a;CPU2.0GHz 内存4G(或更高&#xff0c;不支…

【Unity小技巧】如何在 Unity 中使用我们的Cinemachine虚拟相机跟踪多个目标

文章目录 每篇一句前言安装虚拟相机跟随多个目标和间隙占比代码控制添加主角目标代码控制添加敌人目标扩展代码如何实现虚拟相机跟随玩家呢&#xff1f;我们来实现一下修改虚拟相机的视野修改虚拟相机的位置和角度 推荐完结 每篇一句 岂不闻天无绝人之路&#xff0c;只要我想走…

变压器分析

参考方向 如图所示&#xff0c;是变压器的原理图。其中&#xff0c; ϕ \phi ϕ是变压器铁芯的有效磁通&#xff0c; ϕ 1 \phi_1 ϕ1​是主线圈的漏磁通&#xff0c; ϕ 2 \phi_2 ϕ2​是副线圈的漏磁通。图中 u 1 u_1 u1​为初级线圈输入电压&#xff0c; i 1 i_1 i1​为初级…

iOS Autolayout 约束设置【顺序】的重要性!

0x00 顺序不同&#xff0c;结果不同 看图说话 1 代码是这样滴~ 设置好约束&#xff0c;让 4 个按钮&#xff0c;宽度均分~ 结果如上图 [_pastButton.topAnchor constraintEqualToAnchor:_textView.bottomAnchor constant:6].active YES;[_pastButton.leftAnchor constraintEq…

电子学会C/C++编程等级考试2023年05月(四级)真题解析

C/C等级考试&#xff08;1~8级&#xff09;全部真题・点这里 第1题&#xff1a;怪盗基德的滑翔翼 怪盗基德是一个充满传奇色彩的怪盗&#xff0c;专门以珠宝为目标的超级盗窃犯。而他最为突出的地方&#xff0c;就是他每次都能逃脱中村警部的重重围堵&#xff0c;而这也很大程度…

云原生安全:如何保护云上应用不受攻击

文章目录 云原生安全的概念1. 多层次的安全性2. 自动化安全3. 容器安全4. 持续监控5. 合规性 云原生安全的关键挑战1. 无边界的环境2. 动态性3. 多云环境4. 容器化应用程序5. API和微服务 如何保护云上应用不受攻击1. 身份验证和访问控制示例代码&#xff1a; 2. 数据加密示例代…

Python时间序列分析库介绍:statsmodels、tslearn、tssearch、tsfresh

时间序列分析在金融和医疗保健等领域至关重要&#xff0c;在这些领域&#xff0c;理解随时间变化的数据模式至关重要。在本文中&#xff0c;我们将介绍四个主要的Python库——statmodels、tslearn、tssearch和tsfresh——每个库都针对时间序列分析的不同方面进行了定制。这些库…