29. 一道简单背包题

目录

题目

思路

注意事项

 C++完整代码


题目

Description
龙神有很多背包,每一个背包都有一个容积。但是这些背包的容积都恰好是一个数字的整数倍,比如,,等等。并且对于任意,容积为的背包都存在。
龙神有一些物品要装进背包,第个物品占据的体积。现在,龙神想选出一些物品,使得存在一个背包可以恰好放下这些物品,并且这个背包放满。
龙神想知道这样的取法有多少个,请你帮他算一算吧?由于取法很多,你只需要输出取法的末七位数,没有前导零,即可(即对10000000取模)。
Input
第一行两个数,分别表示物品数和背包体积的基数。
第二行个数,分别表示每个物品的体积。
Output
输出一行一个数,表示取法总数的末七位。

测试输入期待的输出时间限制内存限制额外进程
测试用例 1以文本方式显示
  1. 4 5↵
  2. 1 2 3 2↵
以文本方式显示
  1. 3↵
1秒64M0


思路

1.确定dp数组及其下标的含义

dp数组用于记录背包容量为j时的取法总数,其下标表示背包容量。

数组dp的长度为2*V+1,其中V是背包体积的基数。

2.确定递推公式

对于每个物品i,背包容量j,存在递推公式dp[j] = dp[j] + dp[j - p[i]]。其中,dp[j]代表当前背包容量j下的取法总数,dp[j-p[i]]表示加上当前物品体积后的背包容量(即j-p[i])下的取法总数。

3.dp数组初始化

首先将dp数组所有元素都初始化为0。然后初始化dp[0] = 1,表示背包容量为0时有一种取法。

4.遍历顺序

使用两个嵌套的for循环进行遍历。

外层循环遍历每个物品,内层循环从背包容量的最大值2V递减到物品体积p[i]。

这种遍历顺序确保在计算dp[j]时,可以利用上一轮计算的dp[j-p[i]]的值。另外,为了保证在更新dp[j]时,不影响后续计算,第二个内层循环是从2V递减到p[i]的,这样可以避免重复更新dp[j-p[i]]


注意事项

  1. 题目要求输出取法总数的末七位数,即对结果取模10000000。在代码中,对dp数组元素进行累加操作时,要注意取模运算,以防止数值溢出。

  2. 题目给出了背包容量的基数V,即背包容量都是V的整数倍。在读取每个物品的体积后,需要对其进行取模运算,以保证它们都能装进背包,如果取模结果为0,则将其置为V。

  3. 使用long long存储数据


 

 C++完整代码

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n, V;
    cin >> n >> V;

    // 创建一个长度为n+1的数组p来存储每个物品的体积
    vector<long long> p(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> p[i];
        p[i] %= V;
        if (p[i] == 0)
            p[i] = V;
    }

    // 初始化dp数组,长度为2*V+1,用来记录背包容积为i时的取法总数
    vector<long long> dp(2 * V + 1, 0);
    dp[0] = 1;

    // 动态规划求解
    for (int i = 1; i <= n; i++) {
        for (int j = 2 * V; j >= p[i]; j--) {
            // 更新dp[j]为原来的值加上dp[j-p[i]]
            dp[j] = (dp[j] + dp[j - p[i]]) % 10000000;
        }

        for (int j = 2 * V; j >= p[i]; j--) {
            if (j > V) {
                // 如果背包容积j大于V,则将dp[j-V]加上dp[j],并将dp[j]置为0
                dp[j - V] = (dp[j - V] + dp[j]) % 10000000;
                dp[j] = 0;
            }
        }
    }

    // 输出答案,即背包容积为V时的取法总数的末七位数
    cout << dp[V] % 10000000 << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

榆榆欸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值