砝码称重
[NOIP1996 提高组] 砝码称重
题目描述
设有 \(1\mathrm{g}\)、\(2\mathrm{g}\)、\(3\mathrm{g}\)、\(5\mathrm{g}\)、\(10\mathrm{g}\)、\(20\mathrm{g}\) 的砝码各若干枚(其总重$ \le 1000$),可以表示成多少种重量?
输入格式
输入方式:\(a_1 , a_2 ,a_3 , a_4 , a_5 ,a_6\)
(表示 \(1\mathrm{g}\) 砝码有 \(a_1\) 个,\(2\mathrm{g}\) 砝码有 \(a_2\) 个,…,\(20\mathrm{g}\) 砝码有 \(a_6\) 个)
输出格式
输出方式:Total=N
(\(N\) 表示用这些砝码能称出的不同重量的个数,但不包括一个砝码也不用的情况)
样例 #1
样例输入 #1
1 1 0 0 0 0
样例输出 #1
Total=3
提示
【题目来源】
NOIP 1996 提高组第四题
分析
dp[i][j] 表示在前 i 种砝码中选择物品,使得总重量恰好为 j 的情况下,所能称出的不同重量的方法数。
具体来说,dp[i][j] 记录了在考虑前 i 种砝码时,总重量为 j 的情况下,有多少种不同的方法可以实现这个总重量。
在动态规划的过程中,我们通过状态转移来逐步填充 dp 数组,使得每个位置的值都表示一个特定的情况下的方法数。最终,dp[6][j] 中的值表示使用所有砝码,总重量为 j 的情况下,有多少种不同的方法可以实现这个总重量。
代码实现
#include <bits/stdc++.h>
using namespace std;
int a[7] = {0, 1, 2, 3, 5, 10, 20};
int cot[6];
int dp[7][1005]; // dp[i][j] 表示使用前 i 个砝码,总重量为 j 的情况下,能够称出的不同重量的方法数
int main() {
for (int i = 0; i < 6; i++) cin >> cot[i];
dp[0][0] = 1; // 初始化,表示在前 0 个砝码中选择物品,使得总重量为 0 的情况有 1 种方法
// 动态规划计算
for (int i = 1; i <= 6; i++) {
for (int j = 0; j <= 1000; j++) {
dp[i][j] = dp[i - 1][j]; // 不使用第 i 个砝码时,方法数与前 i-1 个砝码的方法数相同
for (int k = 1; k <= cot[i - 1]; k++) {
if (j >= k * a[i]) {
dp[i][j] += dp[i - 1][j - k * a[i]]; // 使用第 i 个砝码 k 次后,将总重量减少 k*a[i],方法数累加
}
}
}
}
int total = 0;
for (int i = 1; i <= 1000; i++) {
if (dp[6][i]) {
total++; // 统计能够称出的不同重量的个数
}
}
cout << "Total=" << total << endl;
return 0;
}

浙公网安备 33010602011771号