Backpack problem-3. Completely backpack

Complete knapsack problem

#include <iostream>
#define read(x,y) scanf("%d%d",&x,&y)

using namespace std;

const int maxn=1010,maxv=1010;
int v[maxn],w[maxn];
int dp[maxv];

int main() {
    
    
    int N,V;
    read(N,V);
    for (int i=1;i<=N;i++) read(v[i],w[i]);

    for (int i=1;i<=N;i++)
        for (int j=v[i];j<=V;j++)
            dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
         
    printf("%d",dp[V]);

    return 0;
}

Title description

There are N 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 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. Output the maximum value.

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

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 sample

4 5
1 2
2 4
3 4
4 5

Sample output:

10

analysis:

Simple 01 backpack is to choose from N items, each item can only be used once, the complete backpack is different, each item can be used unlimited times.

Therefore, each item in the 01 backpack can only be selected (1) or not (0). In a complete backpack, assuming that the backpack has a volume of V, there can be k+1 states for an item with a volume of v , Which satisfies k*v<=V, corresponds to selecting the item 0, 1, 2...k times.

01 Backpack:
If the item can be put into the backpack, the dynamic transfer equation is dp[i][j]=max( dp[i-1][j],dp[i-1][ j-v[i] ]+ w[i] ), j>=w[i]
If the item cannot be put into the backpack dp[i][j]=dp[i-1][j] , j<w[i]

Complete knapsack: The
dynamic transfer equation satisfies:, dp[i][j]=max{dp[i-1][ j-k×v[i] ] + k×w[i]}where 0 ≤ k×w[i] ≤ j, it
can be found that the special case when k can only take 0 and 1 is the simple 0-1 knapsack problem.

It can be found that if you choose 0 times, that is, if you choose not to choose, it is definitely there. dp[i][j]=dp[i-1][j];
Then choose 1 time, then it may not exist. It may be selected or not. Assuming it can be selected, it is calculated after selecting 0 times dp[i][j]. Based on this, determine whether to choose the item: if (j>=v[i]) dp[i][j]=max(dp[i][j],dp[i-1][j-v[i]]+w[i]);
choose 2 times, choose 3 times, and so on, until you choose k times.

The above is the way to write a two-dimensional array in the simple 01 backpack, that is, manually simulate the for loop and loop twice , but in the complete backpack, it loops k times (k>1), but for the 01 backpack with only two choices , You can also use if, else to judge, see rolling array implementation.

Two-dimensional array implementation

#include <iostream>
#define read(x,y) scanf("%d%d",&x,&y)

using namespace std;

const int maxn=1010,maxv=1010;
int v[maxn],w[maxn];
int dp[maxn][maxv];//N行V列,0行0列初始为0

int main() {
    
    
    int N,V;
    read(N,V);
    for (int i=1;i<=N;i++) read(v[i],w[i]);

    for (int i=1;i<=N;i++)
        for (int j=0;j<=V;j++) "已经初始化第0列为0了,所以不管j从1还是从0开始,都一样"
            for (int k=0;k*v[i]<=j;k++)
                dp[i][j]=max(dp[i][j],dp[i-1][j-k*v[i]]+k*w[i]);

    printf("%d",dp[N][V]);

    return 0;
}

In the second recycle above, when j starts from 0, because the volume of the item is greater than 0, it will continue to cycle k*v[i]<=j, so when j=0, it will only cycle once, that is, when no item is selected,, will dp[i][0]=dp[i-1][0]eventually be equal to dp[0][ 0]=0, so when the 0th column is initialized, j starts at 1.

The statement in the double loop The k times of the triple loop can be analogous to the statement in the double loop of the simple 01 backpack. The 01 backpack is a simple way of looping twice, and the complete backpack is looping k times, but in order to dp[i][j]be able to take it for the first time At this point dp[i-1][j], you should dp[i][j]initialize a value less than or equal to 0, because the minimum value of the dp two-dimensional table is 0.

Time complexity optimization

Above to go through the triple loop, time complexity is high, we can f[i, j] = max { f[i-1, j-k*v[i]] + k*w[i] }expand, you can find the following rules:

Assuming that the volume of the i-th item is v and the value is w, at most k items can be packed into a backpack with a volume of j, that is, k*v<=j

For a backpack with a volume of j for the first i items selected:, k items can be loaded at most,

f [ i , j ] = m a x ( f [ i − 1 ] [ j ] , f [ i − 1 ] [ j − v ] + w , f [ i − 1 ] [ j − 2 v ] + 2 w … … f [ i − 1 ] [ j − k v ] + k w ) f[i,j]=max(f[i-1][j],f[i-1][j-v]+w,f[i-1][j-2v]+2w……f[i-1][j-kv]+kw) f[i,j]=max(f[i1][j]f[i1][jv ]+wf[i1][j2 v ]+2 wf[i1][jkv]+kw)

For a backpack with the volume of jv selected from the first i items:, you can load up to k-1 of these items,
f [i, j − v] = max (f [i − 1] [j − v], f [ i − 1] [j − 2 v] + w…… f [i − 1] [j − kv] + (k − 1) w) f[i,jv]=max(f[i-1][jv ], f[i-1][j-2v]+w……f[i-1][j-kv]+(k-1)w)f[i,jv ]=max(f[i1][jv]f[i1][j2 v ]+wf[i1][jkv]+(k1)w)

By substituting the two equally, the optimized state transition equation of the complete knapsack can be obtained. f[i][j]=max(f[i-1][j],f[i][j-v]+w)
Compare the state transition equation of the simple 01 knapsack:f[i][j]=max(f[i-1][j],f[i-1][j-v]+w)

Code

#include <iostream>
#define read(x,y) scanf("%d%d",&x,&y)

using namespace std;

const int maxn=1010,maxv=1010;
int v[maxn],w[maxn];
int dp[maxn][maxv];//N行V列,0行0列初始为0

int main() {
    
    
    int N,V;
    read(N,V);
    for (int i=1;i<=N;i++) read(v[i],w[i]);

    for (int i=1;i<=N;i++)
        for (int j=0;j<=V;j++) {
    
    
            dp[i][j]=dp[i-1][j];
            if (j>=v[i]) dp[i][j]=max(dp[i][j],dp[i][j-v[i]]+w[i]);
        }
    printf("%d",dp[N][V]);

    return 0;
}

There is only one difference. It can be seen that the dp[i][j] of the i-th row of the simple 01 backpack completely depends on the dp[i-1][0] to dp[i-1][j of the i-1th row. ] Data,
and completely knapsack the dp[i][j] of the i-th row depends on a data dp[i-1][j] of the i-1th row and dp[i][0 of the i-th row itself ] To dp[i][j-1] data.

Optimization + one-dimensional array implementation

The updated data in the first few columns of the i-th row in the complete backpack needs to be used by the next few columns, so when one-dimensional array optimization is performed like a simple backpack, the double loop cannot be reversed, but must be positive.

It can be understood that selecting k items from a backpack with a volume of j is also a recursive process. If k items are selected, then k-1 items are selected to find the answer and keep looking down.

If the 01 backpack is also updated in positive order, the data in row i-1 will be overwritten by the newly updated data in row i, but the data in row i-1 will be used later. In order to avoid data damage, so Update in reverse order.

#include <iostream>
#define read(x,y) scanf("%d%d",&x,&y)

using namespace std;

const int maxn=1010,maxv=1010;
int v[maxn],w[maxn];
int dp[maxv];

int main() {
    
    
    int N,V;
    read(N,V);
    for (int i=1;i<=N;i++) read(v[i],w[i]);

    for (int i=1;i<=N;i++)
        for (int j=v[i];j<=V;j++)
            dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
         
    printf("%d",dp[V]);

    return 0;
}

Guess you like

Origin blog.csdn.net/HangHug_L/article/details/114238728