华为OD机试真题—— 小明减肥(2025B卷:100分)Java/python/JavaScript/C/C++/GO最佳实现
2025 B卷 100分 题型
本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式;
并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析;
本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分享》
华为OD机试真题《小明减肥》:
文章快捷目录
题目描述及说明
Java
python
JavaScript
C++
C
GO
题目名称:小明减肥
- 知识点:组合数学、回溯/枚举
- 时间限制:1秒
- 空间限制:256MB
- 限定语言:不限
题目描述
小明有n
个可选运动,每个运动对应一个卡路里值。他需要从中选出k
个运动,使得这些运动的卡路里总和恰好为t
。给定n
、k
、t
及每个运动的卡路里列表,求可行的方案数量。
输入描述
- 第一行输入三个整数:
n
(运动数量,0 < n < 10)、t
(目标卡路里总和,t > 0)、k
(需选的运动数,0 < k ≤ n)。 - 第二行输入
n
个正整数,表示每个运动的卡路里值(均 > 0),以空格分隔。
输出描述
输出满足条件的方案数量(整数)。
示例
输入:
4 3 2
1 1 2 3
输出:
2
解释:可选方案为[1,2]
和[1,2]
(注意重复卡路里值的不同索引视为不同方案)。
Java
问题分析
小明需要从n个运动中选择k个,使得它们的卡路里总和恰好为t。我们需要计算所有符合条件的组合数量。每个运动的卡路里值可能重复,但不同索引视为不同方案。
解题思路
- 回溯枚举:遍历所有可能的k元素组合,统计满足条件的方案数。
- 剪枝优化:在递归过程中,若已选元素超过k或总和超过t,提前终止该路径。
- 索引处理:通过限定遍历起始索引,确保生成的组合是无序且不重复的。
代码实现
import java.util.Scanner;public class Main {private static int n; // 运动总数private static int t; // 目标卡路里总和private static int k; // 需要选的运动数private static int[] calories; // 各运动卡路里值数组private static int result = 0; // 合法方案计数器public static void main(String[] args) {Scanner scanner = new Scanner(System.in);// 读取输入参数n = scanner.nextInt();t = scanner.nextInt();k = scanner.nextInt();calories = new int[n];for (int i = 0; i < n; i++) {calories[i] = scanner.nextInt();}scanner.close();// 调用回溯函数,初始状态:从索引0开始,已选0个,总和0backtrack(0, 0, 0);System.out.println(result);}/*** 回溯函数,递归遍历所有可能的运动组合* @param start 当前处理的起始索引(避免重复组合)* @param count 已选的运动数目* @param sum 当前卡路里总和*/private static void backtrack(int start, int count, int sum) {// 剪枝:已选数目超过k,或总和超过t,直接返回if (count > k || sum > t) {return;}// 找到k个元素组合,判断是否符合总和要求if (count == k) {if (sum == t) {result++; // 符合条件,计数器加一}return; // 无论是否符合,均停止递归}// 遍历当前可选的索引范围 [start, n-1]for (int i = start; i < n; i++) {// 选择当前元素,递归处理下一个索引backtrack(i + 1, count + 1, sum + calories[i]);}}
}
代码解析
-
输入处理
- 读取
n
、t
、k
和卡路里数值数组,存入对应变量。
- 读取
-
回溯函数
backtrack
- 参数说明:
start
确保组合按索引递增生成避免重复;count
记录已选元素数量;sum
记录当前总和。 - 剪枝条件:若当前路径已不可能满足条件(数量超限或总和超限),提前终止。
- 终止条件:当已选元素等于
k
时,检查总和是否等于t
并更新计数器。 - 循环遍历:从
start
开始依次选择元素,递归处理后续元素。
- 参数说明:
示例测试
-
输入示例1
4 3 2 1 1 2 3
输出:
2
解析:选择第0、2元素(1+2)和第1、2元素(1+2)。 -
输入示例2
3 5 2 2 3 4
输出:
1
解析:只有组合(2,3)满足和为5。 -
输入示例3
5 10 3 2 2 3 3 4
输出:
1
解析:组合(3,3,4)符合和为10。
综合分析
-
时间复杂度
- 最坏情况为O(C(n,k)),例如取k个元素的组合数。由于n<10,实际运算量极小。
-
空间复杂度
- 递归栈深度为k,复杂度O(k)。卡路里数组存储为O(n)。
-
正确性保障
- 索引递增:避免重复组合,确保每个组合的唯一性。
- 剪枝优化:提前终止无效路径,提升效率。
-
方案优势
- 简洁高效:递归结构清晰,适用于小规模数据。
- 无重复计算:通过索引递增生成组合,确保每个组合只处理一次。
-
适用场景
- 需要枚举组合的小规模问题(如n≤10),例如算法竞赛或数据分析。
python
问题分析
小明需要从n个运动中选择k个,使其卡路里总和恰好为t。我们需要统计所有满足条件的组合数量,不同索引的同值卡路里视为不同方案。
解题思路
- 回溯枚举:遍历所有可能的k元素组合,统计满足条件的方案数。
- 剪枝优化:在递归过程中,若已选元素超过k或总和超过t,提前终止该路径。
- 索引递增策略:通过固定选择顺序避免重复组合。
代码实现
n, t, k = map(int, input().split())
calories = list(map(int, input().split()))
result = 0def b