执行时长 - 华为OD统一考试(C++ 题解)

alt

题目描述

为了充分发挥GPU算力,需要尽可能多的将任务交给GPU执行,现在有一个任务数组,数组元素表示在这1秒内新增的任务个数且每秒都有新增任务。

假设GPU最多一次执行n个任务,一次执行耗时1秒,在保证GPU不空闲情况下,最少需要多长时间执行完成。

输入描述

第一个参数为GPU一次最多执行的任务个数,取值范围[1, 10000]

第二个参数为任务数组长度,取值范围[1, 10000]

第三个参数为任务数组,数字范围[1, 10000]

输出描述

执行完所有任务最少需要多少秒。

示例1

输入:
3
5
1 2 3 4 5

输出:
6

说明:
一次最多执行 3 个任务,最少耗时 6s。

示例2

输入:
4
5
5 4 1 1 1

输出:
5

说明:
一次最多执行 4 个任务,最少耗时 5s。

题解

题目类型

这道题目属于贪心算法的应用。我们需要在保证GPU不空闲的情况下,尽可能高效地执行所有任务,计算最少需要的时间。

解题思路

  1. 问题分析:题目给定GPU每秒最多执行的任务数n和一个任务数组,数组中的每个元素表示每秒新增的任务数。我们需要计算在GPU不空闲的情况下,执行完所有任务所需的最少时间。
  2. 关键点
    • GPU每秒最多执行n个任务。
    • 如果当前秒的任务数加上之前剩余的任务数超过n,则剩余的任务需要等待后续执行。
    • 最终的时间包括处理所有任务的基本时间(任务数组长度)和处理剩余任务的额外时间。
  3. 方法选择:采用贪心策略,遍历任务数组,实时计算剩余任务数,最后根据剩余任务数计算额外所需的时间。

代码描述

  1. 输入处理:读取输入的三个参数:GPU一次最多执行的任务数n,任务数组长度taskLength,以及任务数组tasks
  2. 计算剩余任务数:遍历任务数组,计算每秒处理后的剩余任务数waitNum。如果当前秒的任务数加上之前的剩余任务数超过n,则更新剩余任务数。
  3. 计算总时间:总时间为任务数组长度加上处理剩余任务所需的额外时间。额外时间的计算采用向上取整的方式,即(waitNum + n - 1) / n
  4. 输出结果:打印计算得到的最少时间。

时间复杂度

  • 时间复杂度:O(m),其中m是任务数组的长度。我们只需要遍历任务数组一次。
  • 空间复杂度:O(m),用于存储任务数组。如果不存储任务数组,可以优化到O(1)。

C++

#include <iostream>
#include <vector>

using namespace std;

int main() {
    // 最多一次执行任务数, 任务长度
    int n, taskLength;
    cin >> n >> taskLength;

    // 任务列表
    vector<int> tasks(taskLength);
    for (int i = 0; i < taskLength; i++) {
        cin >> tasks[i];
    }

    // 等待的任务数量
    int waitNum = 0;
    for (int taskNum : tasks) {
        // 每秒最多n个任务,执行不完则等待后续执行
        waitNum = max(0, waitNum + taskNum - n);
    }

    // 计算任务执行完成
    int costTime = taskLength + (waitNum + n - 1) / n;

    cout << costTime << endl;

    return 0;
}

🙏整理题解不易, 如果有帮助到您,请给点个赞 ‍❤️‍ 和收藏 ⭐,让更多的人看到。🙏🙏🙏

### 流水线问题 C++ 解法 华为 OD 流水线问题要求将多个任务分配到若干条流水线上,使得所有任务完成后的时间最短。解决这个问题的关键在于合理利用优先队列(最小堆)来动态地将新任务分配给当前最早可用的流水线。 以下是一个完整的 C++ 实现: ```cpp #include <iostream> #include <vector> #include <algorithm> #include <queue> using namespace std; int main() { int m, n; cin >> m >> n; vector<int> data(n); for (int i = 0; i < n; i++) { cin >> data[i]; } // 对任务时间进行排序 sort(data.begin(), data.end()); // 创建最小堆,保存每个流水线的完成时间和其编号 priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq; // 将前m个任务分别分配到m条流水线中 for (int i = 0; i < m; i++) { pq.push({data[i], i}); } // 处理剩余的任务 for (int i = m; i < n; i++) { auto top = pq.top(); pq.pop(); top.first += data[i]; // 将当前任务分配给该流水线 pq.push(top); // 更新流水线状态 } // 找出最终最晚完成的时间 while (pq.size() != 1) { pq.pop(); } cout << pq.top().first << endl; } ``` #### 算法说明: - **输入处理**:首先读取流水线数量 `m` 和任务数量 `n`,然后读取所有任务的执行时间。 - **排序任务**:为了尽可能平衡负载,先对任务时间从大到小排序[^2]。 - **优先队列初始化**:将前 `m` 个最大任务时间分配到每条流水线。 - **任务调度**:对于剩余任务,每次取出最早可用的流水线,加上当前任务时间后重新插入队列。 - **结果输出**:最后堆中最大的完成时间即为答案。 --- ### 示例输入与输出 **输入:** ``` 3 5 8 4 3 6 10 ``` **输出:** ``` 12 ``` --- ### 时间复杂度分析 - 排序时间复杂度为 $O(n \log n)$。 - 堆操作(插入和弹出)总共有 $n$ 次,每次操作时间为 $O(\log m)$,因此堆部分总复杂度为 $O(n \log m)$。 - 总体时间复杂度为 $O(n \log n + n \log m)$,适用于较大规模数据处理需求。 --- ### 应用场景 此解法广泛应用于任务调度、资源分配等领域,例如: - 多线程任务分发。 - 分布式系统中的工作节点负载均衡。 - 生产制造中的工序安排。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

什码情况

你的鼓励就是我最大的动力。

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

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

打赏作者

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

抵扣说明:

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

余额充值