Backpack problem-7. Hybrid backpack

Mixed knapsack problem

Title description

There are N items and a backpack with a capacity of V. There are three types of items, each of which has a volume of vi and a value of wi.

Items of the first category can only be used once (01 backpack);
items of the second category can be used unlimited times (full backpack);
items of the third category can only be used si times (multiple backpacks);

Solve which items are loaded into the backpack, so that the total volume of the items does not exceed the capacity of the backpack, 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 three integers vi, wi, si, separated by spaces, indicating the volume, value, and quantity of the i-th item.

si=−1 means the i-th item can only be used once;
si=0 means the i-th item can be used unlimited times;
si>0 means the i-th item can be used si times;

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

Data range
0<N,V≤1000
0<vi,wi≤1000
−1≤si≤1000

Input sample:

4 5
1 2 -1
2 4 1
3 4 0
4 5 2

Sample output:

8

Analysis:
The items in each row of the original two-dimensional dp table are the same type of items, and the same processing methods can be used.
Now the items in each row may be different items, so when updating each row, judge it first Then use the corresponding method to solve the item type and update the row.
It can be divided into two main types: complete backpacks and multiple backpacks. The 01 backpack is a multiple backpack with 1 item usage.

Analyze different situations and perform state transition, as shown in the following figure:

Code

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

using namespace std;

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

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

    for (int i=1;i<=N;i++) {
    
    
        if (s[i]==0) {
    
     //完全背包
            for (int j=v[i];j<=V;j++)  dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
        } else {
    
    
            if (s[i]==-1) s[i]=1; //0-1背包就是特殊的多重背包
            for (int k=1;k<=s[i];k*=2) {
    
    //每个背包挨个拆分
                for (int j=V;j>=k*v[i];j--)  dp[j]=max(dp[j],dp[j-k*v[i]]+k*w[i]);
                s[i]-=k;
            }
            if(s[i]) {
    
    
                for (int j=V;j>=s[i]*v[i];j--)  dp[j]=max(dp[j],dp[j-s[i]*v[i]]+s[i]*w[i]);
            }
        }
    }
    
    printf("%d",dp[V]);

    return 0;
}

You can also save memory , read in once, process once, and process one line at a time.

#include <iostream>

using namespace std;

const int N = 1010;

int n, m;
int f[N];

int main() {
    
    

    cin >> n >> m;
    for (int i = 0; i < n; i++) {
    
    
        int v, w, s;
        cin >> v >> w >> s;
        if (s == 0) {
    
      // 完全背包
            for (int j = v; j <= m; j++) f[j] = max(f[j], f[j - v] + w);
        } else {
    
    
            if (s == -1) s = 1;  // 全部转为多重背包,然后使用二进制优化
            for (int k = 1; k <= s; k *= 2) {
    
    
                for (int j = m; j >= k * v; j--)
                    f[j] = max(f[j], f[j - k * v] + k * w);
                s -= k;
            }
            if (s) {
    
    
                for (int j = m; j >= s * v; j--)
                    f[j] = max(f[j], f[j - s * v] + s * w);
            }
        }
    }
    cout << f[m] << endl;
    return 0;
}

Guess you like

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