华为OD机试真题 新系统 2026-06-07 Python&JS 实现【最佳任务统筹】【200】
目录
题目
某部门的项目经理,近期手头有n个开发任务必须全部完成(不可并行,必须顺序执行)。每个任务有三个属性:
·持续时间duration[i]:执行该任务需要的时间;
·截止时间deadline[i]:任务必须在某个时刻前完成才能获得收益;
收益profit[i]:若在截止时间前完成,可获得的收益。任务从时刻0开始依次执行。若任务i的完成时刻(即开始时刻+duration[i])≤deadline[i]),则你获得profit[i];否则该任务收益为0(任务仍要执行)。他可以任意决定任务的执行顺序,目标是最大化所有任务的总收益。请帮他计算最大可能收益。
输入描述
共有4个输入参数:
1.n:任务数量(1≤n≤20),编号0到n-1。
2.duration:长度为n 的正整数数组,duration[i]≤1000.
3.deadline:长度为n 的正整数数组,deadline|i]≤1000.
4.profit:长度为n的正整数数组,profit[i]≤1000。
输出描述
输出一个整数,表示能获得的最大总收益。样例1
输入
3
2,1,3
3,2,5
10,20,30输出
50
说明按顺序任务2>任务3>任务1执行:
·任务2:时刻0开始,持续1,完成于时刻1≤2,收益20;
·任务3:时刻1开始,持续3,完成于时刻4≤5,收益30;
任务1:时刻4开始,持续2,完成于时刻6>3,收益0。总收益=20+30+0=50,此为最大。
样例2输入
4
1,2,3,4
1,3,6,10
100,200,300,400输出
1000
思路
状态压缩 DP
核心观察
对于任意一个已选任务集合 `mask`,无论这些任务以什么顺序执行,**总耗时是固定的**(等于所有 duration 之和)。因此,在 `mask` 之后加一个新任务时,这个新任务的完成时间也是确定的,跟 `mask` 内部的顺序无关。
这就意味着:我们只需要关心"已经做了哪些任务",不需要关心"具体是先做谁后做谁"——因为总时间只取决于选了的任务集合,不取决于顺序。
状态定义
`dp[mask]` = 完成了集合 `mask` 中的所有任务,能获得的最大收益
边界
`dp[0] = 0`
转移
枚举 mask 中尚未完成的任务 j,把它放到末尾执行:
- 当前时间 = totalTime[mask](mask 中所有任务的总耗时)
- 任务 j 的完成时间 = totalTime[mask] + duration[j]
- 新增收益 = profit[j](如果完成时间 ≤ deadline[j]),否则 0
- `dp[mask | (1<<j)] = max(dp[mask | (1<<j)], dp[mask] + 新增收益)`
正确性证明
对于任意一个任务排列,把它按顺序逐个加入 mask,恰好对应 DP 的一条路径。DP 在每条路径上都取最优,最终 dp[全掩码] 就是全部 n 个任务做完的最大收益。
关键点在于:对于某个 mask,它的总耗时是唯一确定的(duration 之和),所以从 mask 出发加入 j 的完成时间也是唯一确定的——不依赖于 mask 内部的具体执行顺序。因此 DP 不会漏掉任何可能的排列,也不会重复计算。
Code
import sys
def solve(n, duration, deadline, profit):
"""
任务调度最大收益
状态压缩 DP:dp[mask] = 完成 mask 中所有任务的最大收益
"""
# ---- 预处理:计算每种任务子集的总耗时 ----
# totalTime[mask] = mask 中所有任务的 duration 之和
totalTime = [0] * (1 << n)
for mask in range(1, 1 << n):
# lowbit 技巧:取 mask 最低位的 1,得到对应的任务编号
lowbit = mask & -mask
task = (lowbit.bit_length() - 1) # lowbit = 1<<task
prev = mask ^ lowbit
totalTime[mask] = totalTime[prev] + duration[task]
# ---- DP ----
dp = [0] * (1 << n)
for mask in range(1 << n):
curTime = totalTime[mask]
# 尝试将每个尚未完成的任务 j 添加到末尾
for j in range(n):
if mask >> j & 1: # j 已完成,跳过
continue
newMask = mask | (1 << j)
# 任务 j 的完成时间 = curTime + duration[j]
finishTime = curTime + duration[j]
addProfit = profit[j] if finishTime <= deadline[j] else 0
cand = dp[mask] + addProfit
if cand > dp[newMask]:
dp[newMask] = cand
return dp[(1 << n) - 1]
def main():
try:
n_line = sys.stdin.readline()
if not n_line:
return
n = int(n_line.strip())
duration = list(map(int, sys.stdin.readline().strip().split(',')))
deadline = list(map(int, sys.stdin.readline().strip().split(',')))
profit = list(map(int, sys.stdin.readline().strip().split(',')))
print(solve(n, duration, deadline, profit))
except Exception:
print(0)
if __name__ == "__main__":
main()
JS
const readline = require('readline');
/**
* 任务调度最大收益
* @param {number} n 任务数量
* @param {number[]} duration 持续时间数组
* @param {number[]} deadline 截止时间数组
* @param {number[]} profit 收益数组
* @returns {number} 最大总收益
*/
function solve(n, duration, deadline, profit) {
const totalMasks = 1 << n;
// ---- 预处理:每种任务子集的总耗时 ----
const totalTime = new Array(totalMasks).fill(0);
for (let mask = 1; mask < totalMasks; mask++) {
const lowbit = mask & -mask;
// lowbit 对应 2^task,用位运算求 task 编号
const task = Math.log2(lowbit);
const prev = mask ^ lowbit;
totalTime[mask] = totalTime[prev] + duration[task];
}
// ---- DP ----
const dp = new Array(totalMasks).fill(0);
for (let mask = 0; mask < totalMasks; mask++) {
const curTime = totalTime[mask];
for (let j = 0; j < n; j++) {
if (mask >> j & 1) continue; // j 已完成
const newMask = mask | (1 << j);
const finishTime = curTime + duration[j];
const addProfit = finishTime <= deadline[j] ? profit[j] : 0;
const cand = dp[mask] + addProfit;
if (cand > dp[newMask]) dp[newMask] = cand;
}
}
return dp[totalMasks - 1];
}
// ---- 主程序 ----
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let lineCount = 0;
let n, duration, deadline, profit;
rl.on('line', (line) => {
try {
line = line.trim();
if (lineCount === 0) {
n = parseInt(line, 10);
lineCount++;
} else if (lineCount === 1) {
duration = line.split(',').map(Number);
lineCount++;
} else if (lineCount === 2) {
deadline = line.split(',').map(Number);
lineCount++;
} else if (lineCount === 3) {
profit = line.split(',').map(Number);
console.log(solve(n, duration, deadline, profit));
rl.close();
}
} catch (e) {
console.log(0);
rl.close();
}
});
【华为od机试真题Python+JS+Java+Go合集】【超值优惠】:Py/JS/Java/Go合集
【华为od机试真题Python】:Python真题题库
【华为od机试真题JavaScript】:JavaScript真题题库
【华为od机试真题Java&Go】:Java&Go真题题库
【华为od机试真题C++】:C++真题题库
【华为od机试真题C语言】:C语言真题题库
【华为od面试手撕代码题库】:面试手撕代码题库
【华为od机试面试交流群】【文章底部有二维码链接,可扫码加交流群】
华为OD机试:二本院校有机会吗?
有机会,但不大,大神除外!机考分数越高越好,所以需要提前刷题。机考通过后,如果没有收到面试邀请,也不要着急,非目标院校面试邀请发的时间比较晚。非目标院校今年有点难,机试至少要考到350分,所以需要疯狂刷题,华为OD机考是有题库的,最好在考前完所有题库题目。华为OD机试:跨专业可以参加华为OD可以,但是如果你的本科院校比较差,上岸概率不大。华为OD机试:华为OD简历被锁定机试通过,性格测试也通过,但是没人联系面试,发现简历被锁定。此时需要主动去联系HR。让他帮助你查询原因。
更多推荐




所有评论(0)