Analysis of the knapsack problem of dynamic programming

Introduction to the backpack problem:

There are N items and a backpack with a capacity of V. Each item has two attributes: volume and value. The volume of the i-th item is vi and the value is wi. Find out which items to pack into the backpack, so that the total volume of these items does not exceed the backpack capacity, and the total value is the largest .
01 backpack problem: each item can only be used once at most. Either 0 times or 1 time .
Complete knapsack problem: each item has an infinite number of choices . We put it in as much as possible to ensure the maximum total value.
Multiple knapsack problem: the number of each item is different, and there are at most si .
Grouping backpack problem: There are N groups of items, and there are several items in each group. Each group can only choose one item at most,
so we can find the backpack problem. In essence, it is to give us a bunch of items. The items have volume, value, and some even have a number limit. We have a backpack with a limited capacity.
What is the total value that we can pack on the premise that the backpack can be loaded? Note: It is not necessary to fill the backpack here.

01 backpack problem

Problem Description

There are N items and a backpack with a capacity of V. Each item can only be used once.

The volume of the i-th item is vi, and the value is wi.

Find out which items to load into the backpack, so that the total volume of these items does not exceed the backpack capacity and the total value is the largest.
Output the maximum value.

Input format The
two integers in the first line, N and V, are separated by a space, indicating the number of items and the volume of the backpack respectively.

Next, there are N rows, each with two integers vi and wi, separated by a space, indicating the volume and value of the i-th item.

Output format
Output an integer, which represents the maximum value.

Data range
0<N,V≤1000
0<vi,wi≤1000
Input example

4 5
1 2
2 4
3 4
4 5

Sample output:

8

Problem-solving ideas

The best way to understand the problem of
dynamic programming : We generally consider dynamic programming from the above two perspectives**, one is state representation, and the other is state calculation**. The so-called state is generally an unknown number. The knapsack problem is a two-dimensional f(i,j). The state representation is that we think about our entire problem and need to be expressed in several dimensions . The knapsack problem is generally two-dimensional. State calculation refers to how we calculate each of our states f(i,j) step by step . At the same time, dynamic programming problems usually need to consider optimization. The optimization of dp dynamic programming is generally an equivalent modification of the dynamic programming code or the state transition equation of dynamic programming . We need to write out the basic form first, and then optimize. The knapsack problem here can actually be optimized into a one-dimensional problem.

State representation can be considered from two angles: one is the collection , and the other is the attribute of the collection . Each of our states actually represents a set , and we have to consider which set f(i,j) represents, for example, the set of all the selection methods of the knapsack problem. Our f(i,j) represents a set, but it stores a number, which is a certain attribute of the set . There are generally three types of attributes: the maximum value in the set (such as the maximum value of the knapsack problem), the minimum value (the minimum cost sum), and the number of elements .
In the 01 knapsack problem, the set represents a bunch of selection methods , that is, which items are selected. That is, the collection of all selection methods. This set satisfies two conditions. The first condition is to consider only the items selected from the first i, and the second condition is that the total volume of the selected items is <=j . The set of all options that meet these two conditions. The attribute is the maximum value of all the options in the set .
The one-sentence explanation is: f(i,j) represents the collection of all the selection methods with a total volume<=j selected only from the first i items, and the number it stores is the maximum value of the total value of each selection method in the set .

For state calculation, we need to consider how each state f(i,j) is calculated. Before that, we can think about it. After we calculate all f(i,j), then the answer is f(N,V) , That is, the set of all the selection methods selected from the first N items and the total volume does not exceed V, f(N,V) represents the maximum value of the total value of the selection methods in the set.
State calculation generally corresponds to the division of sets. If we say f(i,j), state calculation is actually considering how to divide the current set into several smaller subsets, so that each subset can be represented by the previous smaller state . The division in the backpack is a classic division. We can divide the set of f(i,j) into two subsets. In fact , all the selection methods represented by f(i,j) are divided into two categories. One is the selection method that does not contain i, and the other is the selection method that includes i . Subset division requirements are not missed, and sometimes the number of requirements is not repeated.
The selection method without i refers to the collection of all selected from 1 to i and does not contain the i-th element, and the total volume does not exceed j. It is equivalent to the set of all the choices from 1 to i-1, and the total volume does not exceed j. We can use f(i-1,j) . And the biggest value here is that f(i-1,j)
contains the selection method of i, which refers to the collection of all the selection methods from 1 to i, and the total volume does not exceed j, and also contains the selection method of i. How to find this maximum value? Since all of our selection methods here include the i-th item, our goal is to find the most valuable selection method, so we can remove all the i-th item and remove the i-th item in each selection method. Remove it, it does not affect who our maximum is. (If every student in the class adds 10 points to the final grade, whoever is the highest in the front will still be the highest in the back). At this time, it becomes a selection from 1 to i-1. Since the total volume of the i-th item does not exceed j, the total volume of the i-th item does not exceed j-vi. That is to choose from 1 to i-1, and the total volume does not exceed the set of selection methods such as j-vi. That is, the set of f(i-1,j-vi) these options, That is, the maximum value of these options of f(i-1,j-vi). f(i-1,j-vi) is the maximum value of the i-th item removed , f(i-1,j-vi)+wi can get the i-th item from 1 to i and the total volume Does not exceed the maximum value of j .
We get the maximum value with and without i, then the total maximum value is the max of the two. So f(i,j)=Max(f(i-1,j-vi)+wi,f(i-1,j))
Insert picture description here
dynamic programming has no template, but there are the above ideas.

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;
int n,m;        //n件物品,容量为m
int v[N],w[N];  //体积和价值
int f[N][N];    //f表示只从前i种物品中取出体积<=j的最大价值
int main(){
    
    
    cin>>n>>m;
    for(int i=1;i<=n;i++){
    
    
        cin>>v[i];
        cin>>w[i];
    }
    //初始化状态有f[0-n][0-m]
    //从前i种物品中选出体积<=0的最大价值为0
    //从前0种物品中选出体积为任何值的最大价值为0
    //初始化全局变量就全部是0
    
    //求从前i种物品中选出体积<=j的最大价值
    for(int i=1;i<=n;i++){
    
    
        for(int j=1;j<=m;j++){
    
    
            //右边有可能不存在,只有当j>=v[i]的时候才存在,
            if(j>=v[i]){
    
        //如果存在,就考虑选第i种物品和不选第i种物品的最大值
                f[i][j]=f[i-1][j]>f[i-1][j-v[i]]+w[i]?f[i-1][j]:f[i-1][j-v[i]]+w[i];
            }else{
    
      //不存在,就不选
                f[i][j]=f[i-1][j];
            }
        }
    }
    cout<<f[n][m];
    
    return 0;
}

Now we consider the one-dimensional situation. The conversion to one-dimensional is determined by two directions. Let's look at the state transition equation. When calculating f(i,j), only the layer i-1 is used. The i-2 layer is useless, so we can use a rolling array to do it. And whether it is selected or not, it is less than or equal to j, so we can use a one-dimensional array to calculate.

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;
int n,m;        //n件物品,容量为m
int v[N],w[N];  //体积和价值
int f[N];    //f表示只从前面物品中取出体积<=j的最大价值
int main(){
    
    
    cin>>n>>m;
    for(int i=1;i<=n;i++){
    
    
        cin>>v[i];
        cin>>w[i];
    }
    for(int i=1;i<=n;i++){
    
    
        for(int j=m;j>=v[i];j--){
    
    
           f[j]=max(f[j],f[j-v[i]]+w[i]);
        }
    }
    cout<<f[m];
    
    return 0;
}

Complete knapsack problem

Problem Description

There are N types of items and a backpack with a capacity of V. Each item has unlimited pieces available.

The volume of the i-th item is vi, and the value is wi.

Find out which items to load into the backpack, so that the total volume of these items does not exceed the backpack capacity and the total value is the largest.
Output the maximum value.

Input format The
two integers in the first line, N, V, are separated by a space, which respectively indicate the number of objects and the volume of the backpack.

Next, there are N rows, each with two integers vi and wi, separated by a space, respectively representing the volume and value of the i-th item.

Output format
Output an integer, which represents the maximum value.

Data range
0<N,V≤1000
0<vi,wi≤1000
Input example
4 5
1 2
2 4
3 4
4 5
Output example:
10

Problem-solving ideas:

The idea of ​​solving the problem is basically similar to the 01 knapsack. We analyze it in the same way.
We first analyze the state representation. As with the 01 knapsack problem, the state is f[i,j], and the set in the state representation means that all items only consider the first i All options whose total volume is not greater than j. Attribute: indicates the maximum value of the total value.
State calculation: indicates the division of the set. The 01 knapsack problem is divided into two sections, whether to choose or not to choose, that is, whether to choose 0 or 1 for the i-th item. And here we can divide it into many groups according to how many items are selected for the i-th item. The first subset means to choose 0, the second subset means to choose 1, and so on, up to k. We can divide all the selection methods indicated by f[i,j] just now, that is, all the selection methods that only consider the first i items and the total volume is not greater than j, into so many categories, the first is the i-th item Only choose 0, the second is the ith item and only choose 1... We can see what the value of each subset is. The first subset means that the ith item is not selected, and only the first i items are considered, and The i-th item is not selected, which is equivalent to considering only the first i-1 items, and the total volume does not exceed the maximum value of j. We can use f[i-1,j] to represent it. And suppose we choose k items for the i-th item, which can be divided into three steps to find.
1. Remove k items i
2. Find the maximum value after removal. f[i-1],[jk*v[i]]
3. Add back k items i

f[i-1,jk v[i]]+k w[i] . According to the formula, we can find that when k=0, this formula also satisfies the
Insert picture description here
naive approach, but the time complexity is very large, which is O(n*v2)

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;
int n,m;            //物品种类数和背包容积
int v[N],w[N];      //vi和wi表示第i种物品的体积和价值
int f[N][N];        //f[i][j]表示只考虑前i种物品且总体积不超过j的最大价值
int main(){
    
    
    cin>>n>>m;
    for(int i=1;i<=n;i++){
    
    
        cin>>v[i]>>w[i];
    }
    for(int i=1;i<=n;i++){
    
    
        for(int j=0;j<=m;j++){
    
          //体积
            //这里k是不能无限大的,j与v[i]乘积必须要小于等于体积j
            for(int k=0;k*v[i]<=j;k++){
    
    
                f[i][j]=max(f[i][j],f[i-1][j-v[i]*k]+w[i]*k);
            }
        }
    }
    cout<<f[n][m]<<endl;
    return 0;
}

How to optimize it?
We can think about it:
f[i][j]=f[i-1][jv[i]*k]+w[i]*k is
equivalent to

f[i][j]=max(f[i-1][j],f[i-1][j-v]+w,f[i-1][j-2v]+2w,f[i-1][j-3v]+3w...)
f[i][j-v]=max(        f[i-1,j-v],   f[i-1,j-2v]+w,  f[i-1,j-3v]+2w....)

We can find that f[i][j] and f[i][jv] are very similar, except that each item is more than the next by w. For example, where f[i][j]=f[i-1,jv]+w
so f[i,j]=Max(f[i-1,j],f[i-1,jv]+w
Now let's run it again

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;
int n,m;            //物品种类数和背包容积
int v[N],w[N];      //vi和wi表示第i种物品的体积和价值
int f[N][N];        //f[i][j]表示只考虑前i种物品且总体积不超过j的最大价值
int main(){
    
    
    cin>>n>>m;
    for(int i=1;i<=n;i++){
    
    
        cin>>v[i]>>w[i];
    }
    for(int i=1;i<=n;i++){
    
    
        for(int j=0;j<=m;j++){
    
          //体积
            f[i][j]=f[i-1][j];
            if(v[i]<=j){
    
    
                f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);
            }
        }
    }
    cout<<f[n][m]<<endl;
    return 0;
}

We can compare the current equations of the 01 knapsack problem and the complete knapsack problem

f[i,j]=Max(f[i-1,j],f[i-1,j-v]+w)
f[i,j]=Max(f[i-1,j],f[i,j-v]+w)

We can see that the 01 backpack problem is all transferred from the i-1 layer, and the complete backpack is transferred from the i-th layer.

Guess you like

Origin blog.csdn.net/qq_39736597/article/details/114118381