[Learning Data Structures and Algorithms in the Dead of Night | Part 12] Dynamic Programming - Knapsack Problem

 

Table of contents

 Foreword:

 01 backpack problem:

Two-dimensional array ideas:

One-dimensional array ideas:

Summarize:


 Foreword:

      When we learned the theoretical knowledge of dynamic programming, I said that we should introduce the knapsack problem, so today we will explain the knapsack problem.

Here we only introduce the 01 backpack . As for group backpacks and mixed backpacks, which are already at the competition level, they are too difficult, so we won’t study them here.

[Learning Data Structures and Algorithms in the Dead of Night | Article 10] Dynamic Programming_I am a blog of beef-CSDN blog

 01 backpack problem:

The context of the problem is a backpack and a set of items, each with its own value and weight. The goal is to select some items to put into the backpack, so that the total weight of the items put in does not exceed the capacity of the backpack, and the total value is maximized.

Specifically, given n items, their weights are w1, w2, …, wn, their values ​​are v1, v2, …, vn, and the capacity W of a backpack. How to maximize the value of the items obtained without exceeding the capacity of the backpack?

We still strictly follow the five steps of dynamic programming to determine the problem-solving ideas:

Two-dimensional array ideas:

1. The meaning of the dp array and the meaning of the subscript: the meaning of dp[i][j] is the maximum value of putting [0,i] items into the backpack with capacity j.

  • If the current i-th item is not placed, then the maximum value at this time is dp[ i-1] [ j ]
  • If you put the current i-th item, then the maximum value at this time is dp [ i-1 ][ j-weight[i]] + value[i]

2. Derivation of the recursive formula: dp[i][j]= max(dp[ i-1] [ j ],dp [ i-1 ][ j-weight[i]] + value[i])

3. Initialization of the dp array: For how to initialize the dp array, we can use the way of drawing to represent the dp array

 

If we dynamically plan to the red area at this time, the formula dp[i][j]= max(dp[ i-1 ] [ j ] , dp [ i-1 ][ j-weight[i ] ] + value[i]) We can know that the value of this red area must be slowly pushed from the upper left corner area of ​​the entire array. Therefore, at the beginning, we have to initialize all the upper left corners to prevent the situation that cannot be reduced:

 

 As for the specific initialization value, we can know by simply thinking about it. When the capacity of the backpack is 0, it cannot hold anything, then the maximum value is 0, then we initialize the value of the vertical row to 0, which is dp[ i][0] is initialized to 0, and the horizontal line is always loaded with item 0, so as long as the capacity of the backpack is greater than the capacity of item 0, the maximum value is dp[0][j]=value.(item 0).

4. The traversal order of the dp array: For the two for loops of the two-dimensional array, whether it is to facilitate the backpack or the item first is all right.

Then use an example to implement dynamic programming:

#include <iostream>
#include <vector>

using namespace std;

// 定义物品结构体,包含重量和价值
struct Item {
    int weight;
    int value;
};

int knapsack(int W, vector<Item>& items) {
      int size = items.size();
      vector<vector<int>> dp(n + 1, vector<int>(W + 1, 0));

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= W; j++) {
            // 当前物品重量大于背包容量,无法放入背包
            if (items[i - 1].weight > j) {
                dp[i][j] = dp[i - 1][j];
            }
            else {
                // 考虑放入或不放入当前物品的两种情况,取最大值
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - items[i - 1].weight] + items[i - 1].value);
            }
        }
    }

    return dp[n][W]; // 返回最优解
}

int main() {
    int W = 10; // 背包容量

    vector<Item> items = { {2, 6}, {2, 10}, {3, 12} }; // 物品列表

    int maxValue = knapsack(W, items); // 求解最优解

    cout << "最大总价值为: " << maxValue << endl;

    return 0;
}

One-dimensional array ideas:

In one-dimensional array optimization, we only need to create a one-dimensional array whose length is the backpack capacity + 1, which is used to record the optimal solution not exceeding the current backpack capacity. The specific optimization process is as follows:

The original two-dimensional dp array is defined as dp[n + 1][W + 1], where dp[i][j]it represents the optimal solution when selecting an item that does not exceed weight j among the first i items.

Optimize the two-dimensional dp array into a one-dimensional array dp[W + 1], where it dp[j]represents the optimal solution without exceeding the knapsack capacity j.

Optimized code example:

#include <iostream>
#include <vector>

using namespace std;

// 定义物品结构体,包含重量和价值
struct Item {
    int weight;
    int value;
};

int knapsack(int W, vector<Item>& items) {
    int n = items.size();

    // 创建一维dp数组并初始化为0
    vector<int> dp(W + 1, 0);

    for (int i = 0; i < n; i++) {
        for (int j = W; j >= items[i].weight; j--) {
            // 考虑放入或不放入当前物品的两种情况,取最大值
            dp[j] = max(dp[j], dp[j - items[i].weight] + items[i].value);
        }
    }

    return dp[W]; // 返回最优解
}

int main() {
    int W = 10; // 背包容量

    vector<Item> items = { {2, 6}, {2, 10}, {3, 12} }; // 物品列表

    int maxValue = knapsack(W, items); // 求解最优解

    cout << "最大总价值为: " << maxValue << endl;

    return 0;
}

In the above code, we use a one-dimensional array whose length is knapsack capacity + 1 dp[W + 1]to record the optimal solution under the current knapsack capacity. When calculating, we traverse the items from the back to the front, and update the one-dimensional dp array from the back to the front. This ensures that when updating dp[j], what is needed dp[j - items[i].weight]is already the value from the previous round and will not affect the calculation result of the current round. In this way, the purpose of optimizing the two-dimensional dp array into a one-dimensional array can be achieved, and the correct optimal solution can be obtained.

Summarize:

        In this article, we have studied the 01 backpack. In fact, we can find that the dynamic programming problem still has a relatively strong routine. We split the dynamic programming into five parts. We only need to follow these five steps. In fact, it is still very easy to solve the dynamic programming problem. simple.

If my content is helpful to you, please like, comment and bookmark . Creation is not easy, everyone's support is my motivation to persevere!

 

Guess you like

Origin blog.csdn.net/fckbb/article/details/132093877