[Dynamic programming] 01 backpack problem that never rolls over (details)

Article directory


There is such a knapsack problem in dynamic programming, which is quite troublesome. I listen to it once and forget it again in a few days, so I wrote a blog to explain the 01 knapsack problem in detail, and I can understand it without overturning!

insert image description here

Collar link

Question:
There nare items and a mknapsack of size . Given an array Arepresenting the size of each item and an array Vrepresenting the value of each item. What is the maximum total value that can fit into a backpack?

Note:

  1. A[i], V[i], n, mBoth are integers
  2. You can't slice items
  3. The total size of the items you choose to pack into the backpack cannot exceedm
  4. Each item can only be picked up once
  5. m <= 1000 and len(A), len(V)<=100

Thought analysis:

When you get this question, consider with the thinking of ordinary people. If you want to maximize the total value in the backpack, you need to consider nthe volume and value of each item at the same time. After some choices, the optimal combination solution is obtained.

Each piece of this nitem has the possibility of being put in or not.

First of all, you need to consider the size relationship between the volume of the backpack and the items to be put into it.

  1. If an item is fat and it is bigger than a backpack, then there is no possibility of the item being put in, and it will be lost~
  2. If the volume of an item is smaller than that of the backpack, then you need to consider whether it is more valuable to put it in the backpack or not, and choose the more valuable of the two options.

The four angles of converting the above ideas into dynamic programming should be:

  1. 状态定义F(i,j)前i个物品放进大小为j的背包中所获得的最大的价值量

    For example, F(4, 8) represents the amount of value generated by the best combination with the largest value in the backpack considering the situation that the first 4 items are put in when the size of the backpack is 8.

  2. 状态间的转移方程Define F(i,j):

  • At that timeA[i-1] > j , F(i,j)= F(i-1,j); means that the i-th item is larger than the knapsack and discarded. At this time, the value of the knapsack is the same as the maximum value produced by putting the first i-1 items into the knapsack of size j.

  • At that timeA[i-1] <= j , F(i,j)= Max(F(i-1,j),F(i-1,j-A[i-1])+V[i-1]);

    It means that the volume of the i-th item is smaller than that of the backpack, then there is a choice of whether to put it in the backpack or not, and the value of F(i, j) will be the one that can produce the greatest value among the two choices.

    If it is not put into the knapsack, then the value of the knapsack at this time is the same as the maximum value produced by putting the first i-1 items into the knapsack of size j;

    If it is put into a backpack, then the volume of the i-th item (A[i-1]) needs to be vacated in the backpack that has made the best choice for the first i-1 items, and this volume is used to welcome the item. The arrival of i, then add the value of the i-th item (V[i-1]).

  1. 状态的初始化 F(0,j)= F(i,0)= 0;The value of the backpack is 0 when there are no items in it or when the size of the backpack is 0

  2. 返回结果F(n,m)The maximum amount of value generated by putting n items into a knapsack of size m

Example analysis:

There are 4 items here, the size of the backpack is 8, the item size array A[4]={3,5,1,4}; the item value array V[4]={1,3,2,3};

In order to illustrate the problem more vividly, a two-dimensional table is used to verify our previous analysis ideas:

insert image description here

The abscissa is the capacity of the backpack (j), and the ordinate is the item number (i). Each coordinate represents the maximum value obtained by putting the first i items into a backpack of size j.

When there is no item or the capacity of the backpack is 0, the value in the backpack is 0, which is state initialization.

When deciding whether to put size 1 in the backpack:

  • When the capacity of the backpack is less than 3 (the size of item 1), there is no possibility to put item 1 down, and discard it~ At this time, the value of the backpack is 0

  • When the backpack capacity is greater than or equal to 3

    • F(1,3) = max(F(0,3),F(0,3-3)+ V[0]) = F(0,0)+ 1= 1

    • F(1,4)= max(F(0,4),F(0,4-3)+ V[0]) = F(0,1)+ 1 = 1

    • F(1,8) = max(F(0,8),F(0,8-3)+ V[0]) = F(0,5)+ 1= 1

When deciding whether to put size 2 in the backpack:

  • When the capacity of the backpack is less than 5 (the size of item 2), there is no possibility of putting item 2 down, and discard it~. At this time, the value of the backpack is the same as that of F(1, j) (1<=j<=4)
  • When the backpack capacity is greater than or equal to 5
    • F(2,5) = max(F(1,5),F(1,5-5)+ V[1]) = F(1,0)+ 3= 3
    • F(2,6) = max(F(1,6),F(1,6-5)+ V[1]) = F(1,1)+ 3= 3
    • F(2,7) = max(F(1,7),F(1,7-5)+ V[1]) = F(1,2)+ 3= 3
    • F(2,8) = max(F(1,8),F(1,8-5)+ V[1]) = F(1,3)+ 3= 4

When deciding whether to put size 3 in the backpack:

  • When the capacity of the backpack is less than 1 (the size of the item 3), there is no possibility of putting the item 3 down. Discard it~, at this time, the value of the backpack is 0

  • When the backpack capacity is greater than or equal to 1

    • F(3,1) = max(F(2,1),F(2,1-1)+ V[2]) = F(2,0)+ 2= 2

    • F(3,2) = max(F(2,2),F(2,2-1)+ V[2]) = F(2,1)+ 2= 2

    • F(3,8) = max(F(2,8),F(2,8-1)+ V[2]) = F(2,7)+ 2= 5

When deciding whether to put size 4 in the backpack:

  • When the backpack capacity is less than 4 (the size of item No. 4), there is no possibility of putting down the No. 4 item. Discard it~. At this time, the value of the backpack is the same as that of F(3, j) (1<=j<=3)

  • When the backpack capacity is greater than or equal to 4

    • F(4,4) = max(F(3,4),F(3,4-4)+ V[3]) = F(3,4)= 4

    • F(4,5) = max(F(3,5),F(3,5-4)+ V[3]) = F(3,1)+ 3= 5

    • F(4,8) = max(F(3,8),F(3,8-4)+ V[3]) = F(3,4)+ 3= 6

Backtracking induction:

Backtracking from the lower right corner of the table, the maximum value generated by the current i item is equal to the maximum value generated by the previous i-1 item, indicating that the i-th item has not been put into the knapsack, otherwise, it has been put into the knapsack.

In this example

F(4, 8) != F(3, 8) means that item 4 is put into the backpack, and the size of item 4 is 4, which means that there are 4 other items left in the backpack

F(3, 4) != F(2, 4) means that item 3 is put into the backpack, and the size of item 3 is 1, which means that there are 3 other items left in the backpack

F(2, 3) == F(1, 3) means that item 2 is not put into the backpack, and there are 3 other items left in the backpack

F(1, 3) != F(0, 3) means that item 1 is put into the backpack, the size of item 1 is 3, and the capacity of the backpack is 0

Summary: Item 1, Item 3, Item 4 are put into the backpack

Code

public class Solution {
    
    
    public int backPackII(int m, int[] A, int[] V) {
    
    
        int n = A.length;//物品的数量
        if(n == 0 && m == 0) return 0;//若没有物品或背包容量为0,就直接返回0,背包价值为0
        int[][] maxV = new int[n+1][m+1];//创建二维数组来存放价值状态
        //状态初始化
        //在Java中数组被初始化大小后,每个元素的大小默认为0,因此maxV[i][0]和maxV[0][j]不再初始化也是可以的
        for(int i = 0;i <= n;i ++) {
    
    
            maxV[i][0] = 0;
        }
        for(int j = 0;j <= m;j ++) {
    
    
            maxV[0][j] = 0;
        }
        //状态转移
        for(int i = 1;i <= n;i ++) {
    
    
            for(int j = 1;j <= m;j ++) {
    
    
                if(A[i-1] <= j) {
    
    
                    maxV[i][j] = Math.max(maxV[i-1][j],maxV[i-1][j-A[i-1]]+V[i-1]);//背包容量大于物品i的情况
                }else{
    
    
                    maxV[i][j] = maxV[i-1][j];//背包容量小于物品i的情况
                }
            }
        }
        return maxV[n][m];//返回结果
    }
}

code upgrade

In fact, the state transition in the dynamic programming problem refers to the state obtained by transferring one step. In this question, that is to say, the maximum value of the knapsack obtained when the i-th item is placed will only be placed with the i-1-th item. The maximum value of the backpack obtained by entering the situation is related to the maximum value of the backpack obtained by entering the situation. The value of the backpack does not need to be concerned at all, because the dynamic programming problem is to record the status of each small problem, and then deduce the big problem step by step. the process of.

In this case, we can simply create a one-dimensional array of size m (the maximum capacity of the backpack) to store the value of the backpack after the i-1th item is put in or not, and the value of the backpack after the i-th item is put in or not. Change directly in that one-dimensional array.

The idea is the same as above, the difference is that the array becomes one-dimensional. And when the second layer is traversed, it needs to be traversed from the back to the front. If it is traversed from the front to the back, it will appear that when the latter state wants to use the value of the former state, the former state value has been tampered with, and the result The result will naturally be wrong.

A simple example of traversing this from back to front:

array[5] = {1,2,3,4,5};

Now let array[0] remain unchanged, and all other elements in the array become twice as large as the previous element, that is, array[i] = array[i-1]*2 (0<i<5)

Method 1: Recreate an array a[] to store the result, then it doesn't matter whether the array is traversed from front to back or from back to front, the array array has not been tampered with, and the results are all correct

Method 2: In order to save space, simply change it directly on the array array. If it is from front to back, array[0]= 1, array[1]=2, array[2]= 4, array[3]= 8! ?There is a bug, it should not be 6. The reason is that the following results will use the value in front of the array array. Traversing from front to back will tamper with the value in front of the array array, and this situation will not occur from back to front. .

Method 1 is equivalent to creating a two-dimensional array in this case, and method 2 is equivalent to creating a one-dimensional array in this case, so you need to pay attention to the traversal direction, which is very important!

public class Solution {
    
    
    public int backPackII(int m, int[] A, int[] V) {
    
    
        int n = A.length;//物品的数量
        if(n == 0 && m == 0) return 0;//若没有物品或背包容量为0,就直接返回0,背包价值为0
        int[] maxV = new int[m+1];//创建一维数组来存放价值状态
        for(int j = 0;j <= m;j ++) {
    
    
            maxV[j] = 0;
        }
        for(int i = 1;i <= n;i ++) {
    
    
            for(int j = m;j >=0;j --) {
    
    
                if(A[i-1] <= j) {
    
    
                    maxV[j] = Math.max(maxV[j],maxV[j-A[i-1]]+V[i-1]);
                }
            }
        }
        return maxV[m];
    }
}

Finish!

Guess you like

Origin blog.csdn.net/weixin_46103589/article/details/121979291