当前位置:首页 > 题解目录 > 正文内容

【题解—动态规划】背包问题1

亿万年的星光5年前 (2021-01-29)题解目录2490

【题目描述】

一个旅行者有一个最多能装 m 公斤物品的背包,现在有 n 件物品,它们的重量分别是 w1,w2,…,wn, 它们的价值分别为 c1,c2,…cn 。若每种物品只有一件,求旅行者能获得的最大总价值。

【输入】

第一行:两个整数 m (背包容量, m ≤ 200 )和 n (物品数量, n ≤ 30 );

第二 行到第n+1 行:每行两个整数 wi,ci, 表示每个物品的重量和价值。

【输出】

一个数据,表示最大总价值。

【输入样例】

10 4
2 1
3 3
4 5
7 9

【输出样例】

12



【题目分析】

  1. 0-1背包问题,用动态规划思路。

  2. 在限重m的情况下求最大价值。


  1. 定义状态

    • 定义 dp[j] 为当前背包容量为 j 时可以获得的最大总价值。

    • 我们需要一个数组 dp 来保存每个容量下的最大价值,初始时所有值都设为0,因为当背包容量为0时,能放入的价值自然也为0。

  2. 状态转移方程

    • 每次考虑第 i 件物品,它的重量和价值分别为 weights[i] 和 values[i]

    • 如果我们决定将这个物品放入背包,并且当前背包的剩余容量足够(即 j >= weights[i]),那么可以得到新的状态: dp[j] = max(dp[j], dp[j - weights[i]] + values[i]) 

    • 这里 dp[j - weights[i]] + values[i] 是将第 i 件物品放入背包后的总价值,而 dp[j] 是不放入它的总价值。取二者的最大值就是我们要更新的新状态。

  3. 更新顺序

    • 为了避免在单次迭代中多次使用同一物品,必须从背包容量 m 向下遍历到 weights[i](即 j-- 的方向)。如果从前往后更新,会导致当前物品的状态被多个引用覆盖。


核心代码:

// 动态规划处理
for (int i = 0; i < n; i++) {
    for (int j = m; j >= weights[i]; j--) {
        dp[j] = max(dp[j], dp[j - weights[i]] + values[i]);
    }
}
  • 外层循环 (for (int i = 0; i < n; i++))

    • 遍历所有物品。如果有 n 个物品,循环此步骤 n 次。

  • 内层循环 (for (int j = m; j >= weights[i]; j--))

    • 从背包的最大容量 m 开始倒序遍历到 weights[i]。这样只会影响当前物品和之前物品的组合,而不会影响未来物品的计算。

  • 状态更新

  • dp[j] 代表当前容量 j 的最大价值,通过与将当前物品放入背包后的新计算值进行比较,选取较大的那个作为新的最大价值。




【参考代码】


#include <iostream>
#include <algorithm>

using namespace std;

int main() {
    int m, n;
    cin >> m >> n; // 读取背包容量 m 和物品数量 n

    int weights[30]; // 存放物品重量,大小为最大数量 n
    int values[30];  // 存放物品价值,大小为最大数量 n
    int dp[201] = {0}; // dp 数组初始化,大小为最大容量 m + 1,初始值为 0

    // 读取每个物品的重量和价值
    for (int i = 0; i < n; i++) {
        cin >> weights[i] >> values[i];
    }

    // 动态规划处理
    for (int i = 0; i < n; i++) {
        for (int j = m; j >= weights[i]; j--) {
            dp[j] = max(dp[j], dp[j - weights[i]] + values[i]);
        }
    }

    // 输出最大总价值
    cout << dp[m] << endl;

    return 0;
}



扫描二维码推送至手机访问。

版权声明:本文由青少年编程知识记录发布,如需转载请注明出处。

分享给朋友:

相关文章

【题解】同学的等待

【题目描述】同学们下课后去食堂,每个人都需要一段时间去点菜。然而,某些同学点菜时间太长了。同学们对于等待很烦躁:他们希望,能尽量少的花时间等待。(同学数<=100000),(0<=点菜耗时...

【题解】上学线路(2019青岛市程序设计比赛)

【题解】上学线路(2019青岛市程序设计比赛)

 【题目描述】小D从家到学校的道路结构是这样的:由n条东西走向和m条南北走向的道路构成了一个n*m的网格,每条道路都是单向通行的(只能从北向南,从西向东走)。已知小D的家在网格的左上角,学校...

【题解】黑白棋子移动

【题目描述】有2n个棋子(n≥4)排成一行,开始位置为白子全部在左边,黑子全部在右边,如下图为n=5的情形:○○○○○●●●●●移动棋子的规则是:每次必须同时移动相邻的两个棋子,颜色不限,可以左移也可...

【题解】前缀最小值

【题目描述】求一个数列的所有前缀最小值之和。即:给出长度为n的数列a[i],求出对于所有1<=i<=n,min(a[1],a[2],...,a[i])的和。由于读入较大,数列由随机种子生成...

【题解】跳格子2

【题目描述】地面上有一排长度为n的格子1-n,每个格子上都有一个数xi,开始时你在位置0,每次你可以向前跳1-2格,然后取走格子上的数,直到跳到位置n+1。取走的数的和就是你的得分,现在你想知道你可能...

连词成句

【题目描述】有一天,毛毛上课的时候遇到了一个难题,老师让同学们把黑板上的单词连成一句话。已知连词的规则是:从待选词中选出正确的单词按照顺序输出,“正确的单词”表示除第一个单词外,其余单词都是小写字母,...