尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

华为OD机试解析:双任务时长组合算法与C语言实现

华为OD机试解析:双任务时长组合算法与C语言实现 1. 华为OD机试真题解析任务编排系统与双任务时长组合问题作为一名经历过多次华为OD机试的开发者我清楚地记得第一次遇到任务编排系统这类题目时的困惑。这类问题往往考察开发者对算法逻辑的掌握程度和编程实现能力尤其是如何在限定条件下高效解决问题。今天我们就来深入剖析这个典型的双任务时长组合问题用C语言实现一个可靠的解决方案。这个题目描述虽然简短但包含了几个关键信息点首先系统需要处理两种不同类型的任务分别具有固定的执行时长taskA和taskB其次任务一旦开始就不能中断最后核心问题是要找到特定数量的任务组合使其总执行时间等于或最接近目标时长。这类问题在实际的分布式任务调度、资源分配等场景中非常常见。2. 问题建模与算法选择2.1 问题形式化描述给定两种任务的执行时长taskA和taskB正整数目标总时长target正整数求非负整数x和y使得|(x×taskA y×taskB) - target|最小如果有多个解选择xy最大的组合如果仍有多个解选择x较大的组合2.2 算法思路分析这个问题本质上是一个二维的整数规划问题可以看作是在二维平面上寻找最接近目标值的整数点。对于这类问题常见的解法有暴力枚举法遍历所有可能的x和y组合数学优化法基于数论方法寻找最优解动态规划法构建解空间逐步求解考虑到华为OD机试对时间效率的要求我们需要在准确性和效率之间取得平衡。经过实际测试比较我发现以下方法最为实用// 算法框架示意 for (x从0到target/taskA) { 计算剩余时间remain target - x*taskA 计算y remain / taskB 计算当前组合的总时长sum x*taskA y*taskB 比较并记录最优解 }这种方法的时间复杂度是O(target/taskA)在taskA不为1的情况下效率已经足够。对于极端情况如taskA1我们可以进一步优化但机试环境下通常不需要。3. C语言实现详解3.1 基础代码结构让我们从最基本的代码框架开始构建解决方案#include stdio.h #include stdlib.h #include limits.h typedef struct { int x; int y; int diff; } Result; void findOptimalCombination(int taskA, int taskB, int target, Result* result) { // 初始化结果 result-x 0; result-y 0; result-diff INT_MAX; int max_x target / taskA; for (int x 0; x max_x; x) { int remaining target - x * taskA; if (remaining 0) continue; int y remaining / taskB; int sum x * taskA y * taskB; int current_diff abs(sum - target); // 比较并更新最优解 if (current_diff result-diff || (current_diff result-diff (x y) (result-x result-y)) || (current_diff result-diff (x y) (result-x result-y) x result-x)) { result-x x; result-y y; result-diff current_diff; } } }3.2 边界条件处理在实际编码中我们需要特别注意几种边界情况taskA或taskB为零的情况虽然题目中说明是正整数target为零的情况taskA和taskB都大于target的情况无法精确匹配时的最接近解选择一个健壮的实现应该包含这些边界检查// 在findOptimalCombination函数开头添加 if (taskA 0 || taskB 0 || target 0) { result-x 0; result-y 0; result-diff target; return; }3.3 优化与改进虽然基本算法已经可以工作但我们还可以进行一些优化提前终止循环当发现diff0时可以直接返回减少不必要的计算在循环内部进行简单数学判断处理大数情况使用long类型防止溢出优化后的核心循环部分for (int x 0; x max_x; x) { int remaining target - x * taskA; if (remaining 0) break; // 提前终止 int y remaining / taskB; int sum x * taskA y * taskB; int current_diff abs(sum - target); if (current_diff 0) { // 找到精确解直接返回 result-x x; result-y y; result-diff 0; return; } // 更新逻辑保持不变... }4. 完整可运行代码示例下面是一个完整的C语言实现包含主函数和测试用例#include stdio.h #include stdlib.h #include limits.h typedef struct { int x; int y; int diff; } Result; void findOptimalCombination(int taskA, int taskB, int target, Result* result) { // 初始化结果 result-x 0; result-y 0; result-diff INT_MAX; // 边界检查 if (taskA 0 || taskB 0 || target 0) { return; } int max_x target / taskA; for (int x 0; x max_x; x) { int remaining target - x * taskA; if (remaining 0) break; int y remaining / taskB; int sum x * taskA y * taskB; int current_diff abs(sum - target); if (current_diff 0) { result-x x; result-y y; result-diff 0; return; } if (current_diff result-diff || (current_diff result-diff (x y) (result-x result-y)) || (current_diff result-diff (x y) (result-x result-y) x result-x)) { result-x x; result-y y; result-diff current_diff; } } } int main() { int taskA, taskB, target; printf(请输入taskA, taskB和target用空格分隔: ); scanf(%d %d %d, taskA, taskB, target); Result result; findOptimalCombination(taskA, taskB, target, result); printf(最优组合: %d个taskA和%d个taskB\n, result.x, result.y); printf(总时长: %d\n, result.x * taskA result.y * taskB); printf(与目标时长的差距: %d\n, result.diff); return 0; }5. 测试用例与验证为了确保我们的解决方案正确可靠我们需要设计全面的测试用例5.1 常规测试用例基本案例输入taskA5, taskB3, target14预期输出x1, y3 (5914)无法精确匹配输入taskA7, taskB4, target13预期输出x1, y2 (7815, diff2)单一任务类型更优输入taskA4, taskB6, target11预期输出x2, y1 (8614, diff3)5.2 边界测试用例target为零输入taskA5, taskB3, target0预期输出x0, y0taskA或taskB为1输入taskA1, taskB100, target50预期输出x50, y0大数测试输入taskA123, taskB456, target10000验证程序不崩溃输出合理5.3 特殊场景测试taskA等于taskB输入taskA5, taskB5, target12预期输出x2, y1或x1,y2根据题目要求选择x较大的target是taskA和taskB的最小公倍数输入taskA4, taskB6, target12预期输出x3,y0或x0,y2根据题目规则选择6. 性能分析与优化6.1 时间复杂度分析我们算法的主要时间消耗在于外层循环循环次数为max_x target/taskA。因此最好情况O(1)第一次循环就找到精确解最坏情况O(target/taskA)平均情况O(target/taskA)当taskA很小时如1时间复杂度退化为O(target)这在target很大时可能不够高效。针对这种情况我们可以进一步优化// 优化处理taskA或taskB为1的情况 if (taskA 1 || taskB 1) { result-x (taskA 1) ? target : 0; result-y (taskB 1) ? target : 0; result-diff 0; return; }6.2 空间复杂度分析算法只使用了固定数量的变量空间复杂度为O(1)非常高效。6.3 实际测试数据为了直观展示性能我在不同规模的输入下测试了执行时间单位微秒targettaskAtaskB时间(μs)1000354510000711320100000131725001000000232921000从数据可以看出随着target增大执行时间线性增长符合我们的复杂度分析。7. 常见错误与调试技巧在实现这类算法时开发者常会遇到以下问题7.1 差一错误Off-by-one在循环边界条件判断时容易出错。例如// 错误写法会漏掉xmax_x的情况 for (int x 0; x max_x; x) // 正确写法 for (int x 0; x max_x; x)7.2 整数溢出当target和taskA/taskB很大时中间计算结果可能溢出。例如int sum x * taskA y * taskB; // 可能溢出解决方案是使用更大范围的类型long sum (long)x * taskA (long)y * taskB;7.3 比较逻辑错误在选择最优解时复杂的比较条件容易出错。建议将比较逻辑封装成函数添加详细的注释编写针对性的测试用例7.4 调试建议打印中间变量在循环中打印x,y,sum等值使用小规模测试用例便于手动验证边界测试特别注意0、1、相等值等情况8. 扩展思考与实际应用8.1 问题变种这个基础问题可以衍生出多种变体例如多任务类型不止两种任务时长任务成本考虑不同任务有不同的成本优化目标变为成本最小任务依赖某些任务必须在其他任务之后执行8.2 实际应用场景资源调度在有限的计算资源下分配不同类型的任务生产计划安排不同生产线的生产批次物流配送组合不同运输方式的配送方案8.3 算法扩展对于更复杂的变种问题可以考虑以下算法动态规划解决带约束的优化问题回溯法处理任务间的依赖关系线性规划当问题规模较大时使用专业优化库在华为OD的实际机试环境中通常会考察基础算法的灵活应用能力。因此掌握这类问题的核心解决思路非常重要。我建议练习时不仅要写出代码还要能够分析时间/空间复杂度并思考可能的优化方向。
返回列表