砝码称重

[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;
}

posted @ 2023-08-30 14:46  LongDz  阅读(54)  评论(0)    收藏  举报