【2024年华为OD机试】 (C卷,200分)- 贪心歌手(JavaScriptJava PythonC/C++)
一、问题描述
问题描述
一个歌手需要从A城前往B城参加演出,必须在T天内到达。途中会经过N座城市,且不能往回走。每两座城市之间的行程天数已知。歌手在每座城市都可以卖唱赚钱,但收入会随着停留天数的增加而递减。具体来说,第一天赚M元,第二天赚M-D元,第三天赚M-2D元,依此类推,直到收入不再减少(即收入不低于0)。歌手到达某座城市的第二天才能开始卖唱,且如果今天卖唱,第二天才能出发。
目标是规划歌手的行程,使得在T天内赚取的总收入最大。
输入输出
-
输入:
- 第一行:T(总天数)和N(途经城市数)。
- 第二行:N+1个数字,表示每两座城市之间的行程天数。
- 接下来N行:每行两个数字M和D,表示每座城市的卖唱收入预期。
-
输出:
- 一个数字,表示歌手最多可以赚多少钱。
解题思路
-
计算可用时间:
- 首先计算所有行程天数的总和
roadCost
,这是必须花费的时间。 - 剩余可用于卖唱的时间为
remain = T - roadCost
。
- 首先计算所有行程天数的总和
-
收入计算:
- 每座城市的收入是递减的,第一天赚M元,第二天赚M-D元,依此类推,直到收入不再减少。
- 因此,每座城市的收入可以表示为一个等差数列。
-
时间分配:
- 需要将
remain
天合理分配给各座城市,以最大化总收入。 - 由于收入递减,优先选择收入较高的天数。
- 需要将
-
优先队列的使用:
- 使用优先队列(最小堆)来记录已经分配的天数中收入最小的天数。
- 当需要分配新的天数时,比较当前城市的收入与优先队列中的最小收入,如果当前收入更高,则替换。
具体步骤
-
初始化:
- 计算
remain
。 - 初始化优先队列。
- 计算
-
遍历城市:
- 对于每座城市,计算在该城市停留不同天数的收入。
- 将收入较高的天数加入优先队列。
-
替换策略:
- 如果优先队列已满(即所有
remain
天已分配),则比较当前城市的收入与优先队列中的最小收入。 - 如果当前收入更高,则替换。
- 如果优先队列已满(即所有
-
计算总收入:
- 最终,优先队列中的所有收入之和即为最大总收入。
示例解析
以题目中的示例为例:
-
输入:
- T = 10,N = 2
- 行程天数:1, 1, 2
- 城市1:M = 120,D = 20
- 城市2:M = 90,D = 10
-
计算:
roadCost
= 1 + 1 + 2 = 4remain
= 10 - 4 = 6
-
分配:
- 城市1:停留3天,收入为120 + 100 + 80 = 300
- 城市2:停留3天,收入为90 + 80 + 70 = 240
- 总收入 = 300 + 240 = 540
通过合理分配时间,歌手可以在6天内赚取540元,这是最优的收入。
总结
本题的关键在于合理分配剩余时间,使得总收入最大化。通过使用优先队列来动态调整收入分配,可以有效地找到最优解。
二、JavaScript算法源码
以下是对代码的详细注释和讲解,帮助理解每一部分的逻辑和实现方式:
代码结构
-
输入处理:
- 使用
readline
模块读取输入数据。 - 解析总天数
t
和城市数量n
。 - 解析每两座城市之间的行程天数,并计算总行程时间
roadCost
。 - 解析每座城市的卖唱收入预期
m
和递减值d
,存储在数组mds
中。
- 使用
-
剩余时间计算:
- 计算剩余可用于卖唱的时间
remain = t - roadCost
。 - 如果
remain <= 0
,说明没有时间可用于卖唱,直接输出0
并结束程序。
- 计算剩余可用于卖唱的时间
-
优先队列的使用:
- 使用数组
pq
模拟优先队列(降序排序),记录每天赚的钱。 - 遍历每座城市,计算在该城市停留每天的收入,并尝试将其加入优先队列。
- 使用数组
-
收入计算与替换策略:
- 对于每座城市,只要当天收入
m > 0
,就继续计算。 - 如果优先队列已满(即
pq.length >= remain
),则比较当前收入m
与优先队列中最小收入pq.at(-1)
:- 如果
m > pq.at(-1)
,说明当前收入更高,替换掉优先队列中最小收入。 - 否则,停止在该城市停留,因为继续停留收入会更低。
- 如果
- 将当前收入
m
加入优先队列,并对队列重新排序(降序)。 - 每天收入减少
d
,继续计算下一天的收入。
- 对于每座城市,只要当天收入
-
输出结果:
- 计算优先队列中所有收入的总和,输出最大总收入。
代码逐行注释
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;void (async function () {// 读取总天数t和城市数量nconst [t, n] = (await readline()).split(" ").map(Number);// 读取每两座城市之间的行程天数,并计算总行程时间roadCostconst roadCost = (await readline()).split(" ").map(Number).reduce((a, b) => a + b);// 读取每座城市的卖唱收入预期m和递减值d,存储在数组mds中const mds = [];for (let i = 0; i < n; i++) {mds.push((await readline()).split(" ").map(Number));}// 计算剩余可用于卖唱的时间remainconst remain = t - roadCost;// 如果没有剩余时间,直接输出0并结束if (remain <= 0) {console.log(0);return;}// 优先队列(降序数组),记录每天赚的钱const pq = [];// 遍历每座城市for (let [m, d] of mds) {// 只要在当前城市还有钱赚(m > 0),就继续停留while (m > 0) {// 如果优先队列已满(即已经分配了remain天)if (pq.length >= remain) {// 比较当前收入m与优先队列中最小收入pq.at(-1)if (m > pq.at(-1)) {// 如果当前收入更高,替换掉优先队列中最小收入pq.pop();} else {// 如果当前收入更低,停止在该城市停留break;}}// 将当前收入m加入优先队列pq.push(m);// 对优先队列重新排序(降序)pq.sort((a, b) => b - a);// 每天收入减少dm -= d;}}// 计算优先队列中所有收入的总和const ans = pq.reduce((a, b) => a + b);// 输出最大总收入console.log(ans);
})();
代码逻辑详解
-
输入处理:
- 使用
readline
模块逐行读取输入数据。 - 将总天数
t
和城市数量n
解析为数字。 - 将每两座城市之间的行程天数解析为数组,并计算总行程时间
roadCost
。 - 将每座城市的卖唱收入预期
m
和递减值d
解析为数组,存储在mds
中。
- 使用
-
剩余时间计算:
- 计算剩余可用于卖唱的时间
remain = t - roadCost
。 - 如果
remain <= 0
,说明没有时间可用于卖唱,直接输出0
并结束程序。
- 计算剩余可用于卖唱的时间
-
优先队列的使用:
- 使用数组
pq
模拟优先队列,记录每天赚的钱。 - 遍历每座城市,计算在该城市停留每天的收入,并尝试将其加入优先队列。
- 使用数组
-
收入计算与替换策略:
- 对于每座城市,只要当天收入
m > 0
,就继续计算。 - 如果优先队列已满(即
pq.length >= remain
),则比较当前收入m
与优先队列中最小收入pq.at(-1)
:- 如果
m > pq.at(-1)
,说明当前收入更高,替换掉优先队列中最小收入。 - 否则,停止在该城市停留,因为继续停留收入会更低。
- 如果
- 将当前收入
m
加入优先队列,并对队列重新排序(降序)。 - 每天收入减少
d
,继续计算下一天的收入。
- 对于每座城市,只要当天收入
-
输出结果:
- 计算优先队列中所有收入的总和,输出最大总收入。
示例运行
输入:
10 2
1 1 2
120 20
90 10
运行过程:
- 计算总行程时间
roadCost = 1 + 1 + 2 = 4
。 - 计算剩余时间
remain = 10 - 4 = 6
。 - 遍历城市:
- 城市1:收入
120, 100, 80
,加入优先队列[120, 100, 80]
。 - 城市2:收入
90, 80, 70
,替换优先队列中的最小收入80
,最终队列为[120, 100, 90, 80, 70]
。
- 城市1:收入
- 计算总收入
120 + 100 + 90 + 80 + 70 = 540
。
输出:
540
总结
代码通过优先队列动态调整收入分配,确保在有限的时间内赚取最大收入。逻辑清晰,注释详细,适合理解贪心算法的应用场景。
三、Java算法源码
以下是Java代码的详细注释和讲解,帮助理解每一部分的逻辑和实现方式:
代码结构
-
输入处理:
- 使用
Scanner
读取输入数据。 - 解析总天数
t
和城市数量n
。 - 解析每两座城市之间的行程天数,并计算总行程时间
roadCost
。 - 解析每座城市的卖唱收入预期
m
和递减值d
,存储在二维数组mds
中。
- 使用
-
剩余时间计算:
- 计算剩余可用于卖唱的时间
remain = t - roadCost
。 - 如果
remain <= 0
,说明没有时间可用于卖唱,直接返回0
。
- 计算剩余可用于卖唱的时间
-
优先队列的使用:
- 使用
PriorityQueue
(小顶堆)记录每天赚的钱。 - 遍历每座城市,计算在该城市停留每天的收入,并尝试将其加入优先队列。
- 使用
-
收入计算与替换策略:
- 对于每座城市,只要当天收入
m > 0
,就继续计算。 - 如果优先队列已满(即
pq.size() >= remain
),则比较当前收入m
与优先队列中最小收入pq.peek()
:- 如果
m > pq.peek()
,说明当前收入更高,替换掉优先队列中最小收入。 - 否则,停止在该城市停留,因为继续停留收入会更低。
- 如果
- 将当前收入
m
加入优先队列。 - 每天收入减少
d
,继续计算下一天的收入。
- 对于每座城市,只要当天收入
-
输出结果:
- 计算优先队列中所有收入的总和,返回最大总收入。
代码逐行注释
import java.util.PriorityQueue;
import java.util.Scanner;public class Main {static int t; // 总天数static int n; // 城市数量static int roadCost; // 总行程时间static int[][] mds; // 每座城市的卖唱收入预期public static void main(String[] args) {Scanner sc = new Scanner(System.in);// 读取总天数t和城市数量nt = sc.nextInt();n = sc.nextInt();// 读取每两座城市之间的行程天数,并计算总行程时间roadCostroadCost = 0;for (int i = 0; i < n + 1; i++) {roadCost += sc.nextInt();}// 读取每座城市的卖唱收入预期m和递减值d,存储在二维数组mds中mds = new int[n][2];for (int i = 0; i < n; i++) {mds[i][0] = sc.nextInt(); // mmds[i][1] = sc.nextInt(); // d}// 输出最大总收入System.out.println(getResult());}public static int getResult() {// 计算剩余可用于卖唱的时间remainint remain = t - roadCost;// 如果没有剩余时间,直接返回0if (remain <= 0) {return 0;}// 优先队列(小顶堆),记录每天赚的钱PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> a - b);// 遍历每座城市for (int[] md : mds) {// 第一天卖唱可以赚m,后续每天的收入会减少dint m = md[0];int d = md[1];// 只要在当前城市还有钱赚(m > 0),就继续停留while (m > 0) {// 如果优先队列已满(即已经分配了remain天)if (pq.size() >= remain) {// 比较当前收入m与优先队列中最小收入pq.peek()if (m > pq.peek()) {// 如果当前收入更高,替换掉优先队列中最小收入pq.poll();} else {// 如果当前收入更低,停止在该城市停留break;}}// 将当前收入m加入优先队列pq.add(m);// 每天收入减少dm -= d;}}// 计算优先队列中所有收入的总和return pq.stream().reduce(Integer::sum).orElse(0);}
}
代码逻辑详解
-
输入处理:
- 使用
Scanner
读取输入数据。 - 解析总天数
t
和城市数量n
。 - 解析每两座城市之间的行程天数,并计算总行程时间
roadCost
。 - 解析每座城市的卖唱收入预期
m
和递减值d
,存储在二维数组mds
中。
- 使用
-
剩余时间计算:
- 计算剩余可用于卖唱的时间
remain = t - roadCost
。 - 如果
remain <= 0
,说明没有时间可用于卖唱,直接返回0
。
- 计算剩余可用于卖唱的时间
-
优先队列的使用:
- 使用
PriorityQueue
(小顶堆)记录每天赚的钱。 - 遍历每座城市,计算在该城市停留每天的收入,并尝试将其加入优先队列。
- 使用
-
收入计算与替换策略:
- 对于每座城市,只要当天收入
m > 0
,就继续计算。 - 如果优先队列已满(即
pq.size() >= remain
),则比较当前收入m
与优先队列中最小收入pq.peek()
:- 如果
m > pq.peek()
,说明当前收入更高,替换掉优先队列中最小收入。 - 否则,停止在该城市停留,因为继续停留收入会更低。
- 如果
- 将当前收入
m
加入优先队列。 - 每天收入减少
d
,继续计算下一天的收入。
- 对于每座城市,只要当天收入
-
输出结果:
- 计算优先队列中所有收入的总和,返回最大总收入。
示例运行
输入:
10 2
1 1 2
120 20
90 10
运行过程:
- 计算总行程时间
roadCost = 1 + 1 + 2 = 4
。 - 计算剩余时间
remain = 10 - 4 = 6
。 - 遍历城市:
- 城市1:收入
120, 100, 80
,加入优先队列[120, 100, 80]
。 - 城市2:收入
90, 80, 70
,替换优先队列中的最小收入80
,最终队列为[120, 100, 90, 80, 70]
。
- 城市1:收入
- 计算总收入
120 + 100 + 90 + 80 + 70 = 540
。
输出:
540
总结
代码通过优先队列动态调整收入分配,确保在有限的时间内赚取最大收入。逻辑清晰,注释详细,适合理解贪心算法的应用场景。
四、Python算法源码
以下是Python代码的详细注释和讲解,帮助理解每一部分的逻辑和实现方式:
代码结构
-
输入处理:
- 使用
input()
读取输入数据。 - 解析总天数
t
和城市数量n
。 - 解析每两座城市之间的行程天数,并计算总行程时间
roadCost
。 - 解析每座城市的卖唱收入预期
m
和递减值d
,存储在列表mds
中。
- 使用
-
剩余时间计算:
- 计算剩余可用于卖唱的时间
remain = t - roadCost
。 - 如果
remain <= 0
,说明没有时间可用于卖唱,直接返回0
。
- 计算剩余可用于卖唱的时间
-
优先队列的使用:
- 使用
heapq
模块实现小顶堆,记录每天赚的钱。 - 遍历每座城市,计算在该城市停留每天的收入,并尝试将其加入优先队列。
- 使用
-
收入计算与替换策略:
- 对于每座城市,只要当天收入
m > 0
,就继续计算。 - 如果优先队列已满(即
len(pq) >= remain
),则比较当前收入m
与优先队列中最小收入pq[0]
:- 如果
m > pq[0]
,说明当前收入更高,替换掉优先队列中最小收入。 - 否则,停止在该城市停留,因为继续停留收入会更低。
- 如果
- 将当前收入
m
加入优先队列。 - 每天收入减少
d
,继续计算下一天的收入。
- 对于每座城市,只要当天收入
-
输出结果:
- 计算优先队列中所有收入的总和,返回最大总收入。
代码逐行注释
import heapq# 输入获取
t, n = map(int, input().split()) # 读取总天数t和城市数量n
roadCost = sum(map(int, input().split())) # 读取行程天数并计算总行程时间roadCost
mds = [list(map(int, input().split())) for _ in range(n)] # 读取每座城市的m和d,存储在列表mds中# 算法入口
def getResult():# remain是刨去必要的路程时间后,剩余可以用于赚钱的时间remain = t - roadCost# 如果没有剩余时间,直接返回0if remain <= 0:return 0# 优先队列(小顶堆),记录每天赚的钱pq = []# 遍历每座城市for m, d in mds:# 只要在当前城市还有钱赚(m > 0),就继续停留while m > 0:# 如果优先队列已满(即已经分配了remain天)if len(pq) >= remain:# 比较当前收入m与优先队列中最小收入pq[0]if m > pq[0]:# 如果当前收入更高,替换掉优先队列中最小收入heapq.heappop(pq)else:# 如果当前收入更低,停止在该城市停留break# 将当前收入m加入优先队列heapq.heappush(pq, m)# 每天收入减少dm -= d# 计算优先队列中所有收入的总和return sum(pq)# 算法调用
print(getResult())
代码逻辑详解
-
输入处理:
- 使用
input()
读取输入数据。 - 解析总天数
t
和城市数量n
。 - 解析每两座城市之间的行程天数,并计算总行程时间
roadCost
。 - 解析每座城市的卖唱收入预期
m
和递减值d
,存储在列表mds
中。
- 使用
-
剩余时间计算:
- 计算剩余可用于卖唱的时间
remain = t - roadCost
。 - 如果
remain <= 0
,说明没有时间可用于卖唱,直接返回0
。
- 计算剩余可用于卖唱的时间
-
优先队列的使用:
- 使用
heapq
模块实现小顶堆,记录每天赚的钱。 - 遍历每座城市,计算在该城市停留每天的收入,并尝试将其加入优先队列。
- 使用
-
收入计算与替换策略:
- 对于每座城市,只要当天收入
m > 0
,就继续计算。 - 如果优先队列已满(即
len(pq) >= remain
),则比较当前收入m
与优先队列中最小收入pq[0]
:- 如果
m > pq[0]
,说明当前收入更高,替换掉优先队列中最小收入。 - 否则,停止在该城市停留,因为继续停留收入会更低。
- 如果
- 将当前收入
m
加入优先队列。 - 每天收入减少
d
,继续计算下一天的收入。
- 对于每座城市,只要当天收入
-
输出结果:
- 计算优先队列中所有收入的总和,返回最大总收入。
示例运行
输入:
10 2
1 1 2
120 20
90 10
运行过程:
- 计算总行程时间
roadCost = 1 + 1 + 2 = 4
。 - 计算剩余时间
remain = 10 - 4 = 6
。 - 遍历城市:
- 城市1:收入
120, 100, 80
,加入优先队列[120, 100, 80]
。 - 城市2:收入
90, 80, 70
,替换优先队列中的最小收入80
,最终队列为[120, 100, 90, 80, 70]
。
- 城市1:收入
- 计算总收入
120 + 100 + 90 + 80 + 70 = 540
。
输出:
540
总结
代码通过优先队列动态调整收入分配,确保在有限的时间内赚取最大收入。逻辑清晰,注释详细,适合理解贪心算法的应用场景。
五、C/C++算法源码:
以下是C语言和C++代码的实现,包含详细的中文注释和讲解:
C语言代码
#include <stdio.h>
#include <stdlib.h>// 比较函数,用于降序排序
int cmp(const void *a, const void *b) {return *((int *) b) - *((int *) a);
}int main() {int t, n;scanf("%d %d", &t, &n); // 读取总天数t和城市数量n// roadCost是A~B城市必需的路程时间int roadCost = 0;for (int i = 0; i < n + 1; i++) {int cost;scanf("%d", &cost); // 读取每段路程的时间roadCost += cost; // 累加总路程时间}// remain是刨去必要的路程时间后,剩余可以用于赚钱的时间int remain = t - roadCost;// 如果没有剩余时间可以用,则赚不到钱if (remain <= 0) {puts("0"); // 输出0return 0;}// 优先队列(降序数组)记录赚到的钱, 即数组尾巴是某天赚的最少的钱int pq[remain + 1]; // 数组模拟优先队列int pq_size = 0; // 优先队列的当前大小for (int i = 0; i < n; i++) {// 第一天卖唱可以赚m,后续每天的收入会减少dint m, d;scanf("%d %d", &m, &d); // 读取当前城市的m和d// 只要在当前城市还有钱赚,那么就继续待while (m > 0) {// 只有remain天可以赚钱,超出的时间不能赚钱,因此需要比较超出的时间赚的钱m,和前面时间中赚的最少的钱pq[pq_size - 1]if (pq_size >= remain) {// pq[pq_size - 1]只可能是某座城市停留的最后一天的赚的钱,因为每座城市都是停留的最后一天赚的钱最少if (m > pq[pq_size - 1]) {// 如果当前城市当天赚的钱m,比前面天里面赚的最少的pq[pq_size - 1]多,那么就赚pq[pq_size - 1]钱的那天时间节约下来,给当天用pq_size--; // 移除最小收入} else {// 如果当前城市当天赚的钱m,比前面天里面赚的最少的pq[pq_size - 1]还少,则当前城市继续待下去赚的钱只会更少,因此没必要呆下去了break;}}// 如果所有城市停留时间没有超出remain天,或者当天是超出的时间,但是比前面赚的最少的一天的赚的更多,则赚m更优pq[pq_size++] = m; // 将当前收入加入优先队列qsort(pq, pq_size, sizeof(int), cmp); // 对优先队列重新排序(降序)// 每天收入减少dm -= d;}}// 计算优先队列中所有收入的总和int ans = 0;for (int i = 0; i < pq_size; i++) {ans += pq[i];}// 输出最大总收入printf("%d\n", ans);return 0;
}
C++代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;// 比较函数,用于降序排序
bool cmp(int a, int b) {return a > b;
}int main() {int t, n;cin >> t >> n; // 读取总天数t和城市数量n// roadCost是A~B城市必需的路程时间int roadCost = 0;for (int i = 0; i < n + 1; i++) {int cost;cin >> cost; // 读取每段路程的时间roadCost += cost; // 累加总路程时间}// remain是刨去必要的路程时间后,剩余可以用于赚钱的时间int remain = t - roadCost;// 如果没有剩余时间可以用,则赚不到钱if (remain <= 0) {cout << 0 << endl; // 输出0return 0;}// 优先队列(降序数组)记录赚到的钱, 即数组尾巴是某天赚的最少的钱vector<int> pq; // 动态数组模拟优先队列for (int i = 0; i < n; i++) {// 第一天卖唱可以赚m,后续每天的收入会减少dint m, d;cin >> m >> d; // 读取当前城市的m和d// 只要在当前城市还有钱赚,那么就继续待while (m > 0) {// 只有remain天可以赚钱,超出的时间不能赚钱,因此需要比较超出的时间赚的钱m,和前面时间中赚的最少的钱pq.back()if (pq.size() >= remain) {// pq.back()只可能是某座城市停留的最后一天的赚的钱,因为每座城市都是停留的最后一天赚的钱最少if (m > pq.back()) {// 如果当前城市当天赚的钱m,比前面天里面赚的最少的pq.back()多,那么就赚pq.back()钱的那天时间节约下来,给当天用pq.pop_back(); // 移除最小收入} else {// 如果当前城市当天赚的钱m,比前面天里面赚的最少的pq.back()还少,则当前城市继续待下去赚的钱只会更少,因此没必要呆下去了break;}}// 如果所有城市停留时间没有超出remain天,或者当天是超出的时间,但是比前面赚的最少的一天的赚的更多,则赚m更优pq.push_back(m); // 将当前收入加入优先队列sort(pq.begin(), pq.end(), cmp); // 对优先队列重新排序(降序)// 每天收入减少dm -= d;}}// 计算优先队列中所有收入的总和int ans = 0;for (int val : pq) {ans += val;}// 输出最大总收入cout << ans << endl;return 0;
}
代码逻辑详解
-
输入处理:
- 读取总天数
t
和城市数量n
。 - 读取每段路程的时间,并计算总行程时间
roadCost
。 - 计算剩余可用于卖唱的时间
remain = t - roadCost
。
- 读取总天数
-
优先队列的实现:
- 使用数组(C语言)或
vector
(C++)模拟优先队列。 - 通过排序(降序)实现优先队列的功能。
- 使用数组(C语言)或
-
收入计算与替换策略:
- 对于每座城市,只要当天收入
m > 0
,就继续计算。 - 如果优先队列已满(即
pq.size() >= remain
),则比较当前收入m
与优先队列中最小收入pq.back()
:- 如果
m > pq.back()
,说明当前收入更高,替换掉优先队列中最小收入。 - 否则,停止在该城市停留,因为继续停留收入会更低。
- 如果
- 将当前收入
m
加入优先队列,并对队列重新排序(降序)。 - 每天收入减少
d
,继续计算下一天的收入。
- 对于每座城市,只要当天收入
-
输出结果:
- 计算优先队列中所有收入的总和,输出最大总收入。
示例运行
输入:
10 2
1 1 2
120 20
90 10
运行过程:
- 计算总行程时间
roadCost = 1 + 1 + 2 = 4
。 - 计算剩余时间
remain = 10 - 4 = 6
。 - 遍历城市:
- 城市1:收入
120, 100, 80
,加入优先队列[120, 100, 80]
。 - 城市2:收入
90, 80, 70
,替换优先队列中的最小收入80
,最终队列为[120, 100, 90, 80, 70]
。
- 城市1:收入
- 计算总收入
120 + 100 + 90 + 80 + 70 = 540
。
输出:
540
总结
- C语言和C++代码通过数组或
vector
模拟优先队列,动态调整收入分配,确保在有限的时间内赚取最大收入。 - 逻辑清晰,注释详细,适合理解贪心算法的应用场景。
六、尾言
什么是华为OD?
华为OD(Outsourcing Developer,外包开发工程师)是华为针对软件开发工程师岗位的一种招聘形式,主要包括笔试、技术面试以及综合面试等环节。尤其在笔试部分,算法题的机试至关重要。
为什么刷题很重要?
-
机试是进入技术面的第一关:
华为OD机试(常被称为机考)主要考察算法和编程能力。只有通过机试,才能进入后续的技术面试环节。 -
技术面试需要手撕代码:
技术一面和二面通常会涉及现场编写代码或算法题。面试官会注重考察候选人的思路清晰度、代码规范性以及解决问题的能力。因此提前刷题、多练习是通过面试的重要保障。 -
入职后的可信考试:
入职华为后,还需要通过“可信考试”。可信考试分为三个等级:- 入门级:主要考察基础算法与编程能力。
- 工作级:更贴近实际业务需求,可能涉及复杂的算法或与工作内容相关的场景题目。
- 专业级:最高等级,考察深层次的算法以及优化能力,与薪资直接挂钩。
刷题策略与说明:
2024年8月14日之后,华为OD机试的题库转为 E卷,由往年题库(D卷、A卷、B卷、C卷)和全新题目组成。刷题时可以参考以下策略:
-
关注历年真题:
- 题库中的旧题占比较大,建议优先刷历年的A卷、B卷、C卷、D卷题目。
- 对于每道题目,建议深度理解其解题思路、代码实现,以及相关算法的适用场景。
-
适应新题目:
- E卷中包含全新题目,需要掌握全面的算法知识和一定的灵活应对能力。
- 建议关注新的刷题平台或交流群,获取最新题目的解析和动态。
-
掌握常见算法:
华为OD考试通常涉及以下算法和数据结构:- 排序算法(快速排序、归并排序等)
- 动态规划(背包问题、最长公共子序列等)
- 贪心算法
- 栈、队列、链表的操作
- 图论(最短路径、最小生成树等)
- 滑动窗口、双指针算法
-
保持编程规范:
- 注重代码的可读性和注释的清晰度。
- 熟练使用常见编程语言,如C++、Java、Python等。
如何获取资源?
-
官方参考:
- 华为招聘官网或相关的招聘平台会有一些参考信息。
- 华为OD的相关公众号可能也会发布相关的刷题资料或学习资源。
-
加入刷题社区:
- 找到可信的刷题交流群,与其他备考的小伙伴交流经验。
- 关注知名的刷题网站,如LeetCode、牛客网等,这些平台上有许多华为OD的历年真题和解析。
-
寻找系统性的教程:
- 学习一本经典的算法书籍,例如《算法导论》《剑指Offer》《编程之美》等。
- 完成系统的学习课程,例如数据结构与算法的在线课程。
积极心态与持续努力:
刷题的过程可能会比较枯燥,但它能够显著提升编程能力和算法思维。无论是为了通过华为OD的招聘考试,还是为了未来的职业发展,这些积累都会成为重要的财富。
考试注意细节
-
本地编写代码
- 在本地 IDE(如 VS Code、PyCharm 等)上编写、保存和调试代码,确保逻辑正确后再复制粘贴到考试页面。这样可以减少语法错误,提高代码准确性。
-
调整心态,保持冷静
- 遇到提示不足或实现不确定的问题时,不必慌张,可以采用更简单或更有把握的方法替代,确保思路清晰。
-
输入输出完整性
- 注意训练和考试时都需要编写完整的输入输出代码,尤其是和题目示例保持一致。完成代码后务必及时调试,确保功能符合要求。
-
快捷键使用
- 删除行可用
Ctrl+D
,复制、粘贴和撤销分别为Ctrl+C
,Ctrl+V
,Ctrl+Z
,这些可以正常使用。 - 避免使用
Ctrl+S
,以免触发浏览器的保存功能。
- 删除行可用
-
浏览器要求
- 使用最新版的 Google Chrome 浏览器完成考试,确保摄像头开启并正常工作。考试期间不要切换到其他网站,以免影响考试成绩。
-
交卷相关
- 答题前,务必仔细查看题目示例,避免遗漏要求。
- 每完成一道题后,点击【保存并调试】按钮,多次保存和调试是允许的,系统会记录得分最高的一次结果。完成所有题目后,点击【提交本题型】按钮。
- 确保在考试结束前提交试卷,避免因未保存或调试失误而丢分。
-
时间和分数安排
- 总时间:150 分钟;总分:400 分。
- 试卷结构:2 道一星难度题(每题 100 分),1 道二星难度题(200 分)。及格分为 150 分。合理分配时间,优先完成自己擅长的题目。
-
考试环境准备
- 考试前请备好草稿纸和笔。考试中尽量避免离开座位,确保监控画面正常。
- 如需上厕所,请提前规划好时间以减少中途离开监控的可能性。
-
技术问题处理
- 如果考试中遇到断电、断网、死机等技术问题,可以关闭浏览器并重新打开试卷链接继续作答。
- 出现其他问题,请第一时间联系 HR 或监考人员进行反馈。
祝你考试顺利,取得理想成绩!