动态规划专题(01):01背包与完全背包

2026.03.30

动态规划求解分为3个步骤:状态->阶段->决策, 最终得到新的状态。

1. 背包问题概念

        背包问题指在一个有容积或重量限制的背包中放入物品,物品有体积、重量、价值等属性,要求在满足背包限制的情况下放置物品,使背包中物品的价值之和最大。根据物品限制条件的不同,背包问题可分为01背包、完全背包、多重背包、分组背包和混合背包等。

混合背包是01背包、完全背包、多重背包、分组背包这4种基本背包问题的混合模型。混合背包通常包括其他4种基本背包问题中的一种或若干种情况。

四种基本背包问题的区别:

01背包   :每种物品只有1个
完全背包:每种物品有无穷多个
分组背包:第i组有cᵢ个物品
多重背包:每种物品有cᵢ个

2. 01背包

        给定n种物品,每种物品都有重量wi​和价值vi​,每种物品只有一个,背包容量为W。求解在不超过背包容量的情况下,将哪些物品放入背包,使背包中的物品价值之和最大。每种物品只有一个,要么不放入(0),要么放入(1),因此称之为01背包。

01背包怎么求解?

(1)确定状态

        dp[i][j]表示前i种物品放入容量为j的背包中获得的最大价值。

(2)划分阶段

        第i阶段处理第i种物品,第i-1阶段处理第i-1种物品。当处理第i种物品时,前i-1种物品已处理完毕,只需考虑第i-1阶段向第i阶段的转移。

        就是说i-1阶段求解完毕,才可以处理第i阶段。也就是说在求解第i阶段的状态时前面的所有阶段的状态都已经处理完毕。

第i种物品放入背包有两种情况,要么放入,要么不放入

  • 分支1:不放入背包

        既然物品i不放入背包,那么问题转化为子问题“将前i−1种物品放入容量为j的背包中获得的最大价值”,最大价值为dp[i−1][j]​。

  • 分支2:放入背包

        如果将物品i放入背包,容量j中肯定是要加上当前物品i的价值v[i],加上物品i后容量只剩下j-w[i],那么问题转化为子问题“将前i−1种物品放入容量为j−w[i]的背包中获得的最大价值dp[i−1][j−w[i]]​”,加上第i种物品的价值v[i],即dp[i−1][j−w[i]] + v[i]​。

原问题转化为子问题:

1.原问题为dp[i][j]的状态,也就是第i阶段背包中放置物品的最大价值,

2.子问题为把i-1个物品放入背包中的最大价值,也就是状态dp[i-1][j-w[i]];

所以如果把物品i放入背包,那么背包中最大价值dp[i][j] = dp[i-1][j-w[i]] + v[i];

(3)决策选择

        若背包容量不足,则不能放入,价值仍为前i-1种物品处理后的结果;若背包容量充足,则考察放入、不放入哪种情况获得的价值更大。最终状态为价值更大者的值。

情况1:dp[i][j] = dp[i−1][j], (容量约束:j<w[i])
情况2:dp[i][j] = max{dp[i−1][j], dp[i−1][j−w[i]]+v[i]}​, (容量约束:j≥w[i]​)

在情况2中为什么要比较放入i的价值大还是不放入i的价值大呢?

因为放入前状态不是dp[i−1][j],而是dp[i−1][j−w[i]],dp[i−1][j−w[i]]不一定比dp[i−1][j]大,也就是说dp[i−1][j−w[i]] + v[i] 也并不一定比dp[i−1][j]大,所以需要进行比较。

(4)边界条件

        dp[0][j]=0,i=0,j=0,…W(不放入物品,i=0背包中价值肯定是0)

        dp[i][0]=0,i=0,…n,j=0(背包容量是0,背包中不能放入任何物品,价值肯定是0)

(5)求解目标

       dp[n][W]

实例讲解1:求解背包最大价值

问题描述

有5个物品,背包的容量为10。求放入背包的最大价值。

物品重量与价值:

  • 重量w[](物品1~5):2,5,4,2,3​​​

  • 价值 v[](物品1~5):6,3,5,4,6

题意理解:

 状态转移方程:

情况1:dp[i][j] = dp[i−1][j],(j<w[i]时照抄上一行)

情况2:dp[i][j] = ​max{dp[i−1][j]​, dp[i−1][j−w[i]]+v[i]}​,(j≥w[i]​)

其中dp[i−1][j]​ (上一行同列),dp[i−1][j−w[i]]+v[i]​ (上一行 j−w[i] 列到 +v[i])

(动态规划过程中每一步的计算结果,最终 dp[n][w] = [5][10]=17为最大价值)

算法分析:时间复杂度为 O(nW),空间复杂度为 O(nW)。

代码示例:动态二维数组

/01dp_00_max_value_00.cc

// 有5个物品,背包的容量为10。求放入背包的最大价值。
// 物品重量与价值:
// 重量w[](物品1~5):2,5,4,2,3​​​
// 价值v[](物品1~5):6,3,5,4,6


// 求解背包最大价值
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

// int vol背包容量, const vector<int> w物品体积或重量, const vector<int> v物品价值
int GetMaxValue(int vol, const vector<int> w, const vector<int> v)
{
    int n = w.size();
    vector<vector<int>> dp(n + 1, vector<int>(vol + 1, 0));
    // 第0列初始化,表示当容量为0时,不能放入任何物品,背包价值为0
    // 其实这里可以不要,因为上文已经初始化,这里只是为了表示注意初始化的意思
    for (int i = 0; i < n; ++i) {
        dp[i][0] = 0;
    }
    // 第0行初始化,表示当放入物品为0,背包价值为0
    // 其实这里可以不要,因为上文已经初始化,这里只是为了表示注意初始化的意思
    for (int j = 0; j < n; ++j) {
        dp[0][j] = 0;
    }
    // 动态规划
    for (int i = 1; i <= n; ++i) {
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值