返回

完全背包问题:从0到1,带领你攻克动态规划中的经典之作!

后端

算法思想与动态转移方程的设计

首先,我们来理解完全背包问题中的“完全”一词所代表的含义。它意味着我们可以无限制地重复利用物品,也就是说,我们可以多次使用同一个物品来装入物品,而不用担心它被用完。

知道了这个问题的特殊性,我们就可以开始着手设计动态转移方程了。我们不妨设dp[i]表示在前i件物品中选择若干件,且总价值不超过j的方案数。

那么,当我们考虑第i件物品时,有两种可能:

  • 选择第i件物品:此时,方案数等于在前i-1件物品中选择若干件,且总价值不超过j-w[i]的方案数。
  • 不选择第i件物品:此时,方案数等于在前i-1件物品中选择若干件,且总价值不超过j的方案数。

综上所述,我们可以得到完全背包问题的动态转移方程:

dp[i] = dp[i - 1] + dp[i - w[i]]

其中,w[i]表示第i件物品的重量。

数组空间的优化

在设计好动态转移方程后,我们就可以开始着手解决完全背包问题了。最直接的方法是使用二维数组来存储dp值,但这种方法会占用大量的空间。为了优化空间,我们可以使用一维数组来存储dp值。

具体来说,我们可以将dp[i]的值存储在dp[i % n]中,其中n是物品总数。这样,我们就只需要一个长度为n的数组来存储dp值,从而优化了空间。

代码实现

int main() {
    int n, m;
    cin >> n >> m;
    vector<int> w(n + 1), v(n + 1);
    for (int i = 1; i <= n; i++) cin >> w[i] >> v[i];
    vector<int> dp(m + 1, 0);
    for (int i = 1; i <= n; i++) {
        for (int j = m; j >= w[i]; j--) {
            dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
        }
    }
    cout << dp[m] << endl;
    return 0;
}

结语

完全背包问题是动态规划中非常经典且基础的题目,也是面试考察频率相当高的一个算法考题。通过本文的讲解,希望你能对完全背包问题有更深入的理解。如果你能掌握完全背包问题的解题思路和步骤,那么你就能在算法面试中大展身手,赢得面试官的青睐。