1. 问题背景与需求解析
这道来自华为机考的"称砝码"题目,表面看是个简单的组合数学问题,实则考察了动态规划在实际场景中的应用能力。题目通常给出n种不同重量的砝码各若干枚,要求计算出这些砝码能够称出的所有不同重量组合。
在实际工作中,这类问题常见于物流称重、实验室测量、工业生产等需要精确计量场景。比如快递公司需要知道现有砝码组合能称量哪些包裹重量,药厂需要确认原料配比时能覆盖的称重范围。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心算法思路拆解
2.1 暴力枚举法的局限性
最直观的解法是枚举所有可能的砝码组合。假设有3种砝码,每种最多使用m个,时间复杂度高达O(m^n)。当n=10,m=10时,组合数达到100亿级,显然不可行。
实际机考中,n通常在1-10范围内,每种砝码数量不超过2000个,总重不超过20000
2.2 动态规划解法原理
采用背包问题思路,定义dp数组:
- dp[i]表示重量i能否被称出
- 初始dp[0]=true(重量0总是可达)
- 遍历每种砝码,更新可达重量状态
关键状态转移方程:
python复制for 砝码重量w in weights:
for 数量k in counts:
for j from max_weight downto w*k:
if dp[j - w*k]:
dp[j] = True
2.3 算法优化技巧
- 重量压缩:先计算所有砝码总重max_weight,dp数组只需开到max_weight
- 提前终止:当某种砝码的所有可能组合都无法产生新重量时提前跳出循环
- 砝码去重:合并相同重量的砝码,减少无效计算
3. 完整实现与代码注解
3.1 Python实现示例
python复制def count_weights(weights, counts):
max_weight = sum(w*c for w,c in zip(weights, counts))
dp = [False]*(max_weight + 1)
dp[0] = True
for w, c in zip(weights, counts)
