C++---Knapsack Model---Mixed Knapsack Problem (Daily One Algorithm 2023.3.23)

Note:
This topic is an extended question of "Dynamic Programming - Complete Backpack" and "Dynamic Programming - 01 Backpack" and "dp Dynamic Programming - Multiple Backpacks" . It is recommended to understand these first, which will be of great help to this question.

Problem:
There are N items and a backpack with capacity V.

There are three types of items:
the first type of items can only be used once (01 backpack); the
second type of items can be used unlimited times (full backpack);
the third type of items can only be used si times at most (multiple backpacks); each The volume is vi and the value is wi.

Solve which items to put into the backpack, so that the sum of the volume of the items does not exceed the capacity of the backpack, and the sum of the values ​​is the largest.
output the maximum value.

Input format
The first line contains two integers, N and V, separated by spaces, which respectively represent the number of items and the volume of the backpack.
Then there are N lines, and each line has three integers vi, wi, si, separated by spaces, representing the volume, value and quantity of the i-th item respectively.
si=−1 means that the i-th item can only be used once; si=0 means that the i-th item can be used unlimited times; si>0 means that the i-th item can be used si times;

Output Format
Output an integer representing the maximum value.

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

输入:
4 5
1 2 -1
2 4 1
3 4 0
4 5 2
输出:
8
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1010;
int n, m;
int v[N], w[N], s[N];       //v[i]第i个物品的体积,w[i]第i个物品的价值,s[i]第i个物品的模式(-1为01背包,0为完全背包,大于0为多重背包)
int f[N];

int main() {
    
    
    //读入
    cin >> n >> m;
    for (int i= 1; i<=n; i++) cin >> v[i] >> w[i] >> s[i];

    //dp,三种背包问题的状态表示其实完全一样,都是前i个物品中,体积不超过j时的最大价值,
    //那就直接根据不同的s[i]来进行不同的状态转移即可(这里把01背包视为特殊的多重背包,也就是s[i]为1)
    for (int i= 1; i<=n; i++) {
    
    
        if (s[i] == 0) {
    
     //完全背包
            for (int j = v[i]; j<=m; j++) f[j] = max(f[j], f[j-v[i]]+w[i]);
        }
        else {
    
      //多重背包+二进制优化(二进制优化不理解的话可以取看“多重背包”那篇文章,有详解)
            if (s[i] == -1) s[i] = 1; //将01背包的情况转换为s[i]为1的多重背包
            for (int k = 1; k<=s[i]; k*=2) {
    
    
                for (int j = m; j>=k*v[i]; j--) {
    
    
                    f[j] = max(f[j], f[j-k*v[i]]+k*w[i]);
                }
                s[i] -= k;
            }
            for (int j = m; j>=s[i]*v[i]; j--) {
    
    
                f[j] = max(f[j], f[j-s[i]*v[i]]+s[i]*w[i]);
            }
        }
    }
    cout << f[m];
    return 0;
}

Idea:
The state representations of the three knapsack problems are actually exactly the same,
f[i][j]: among the first i items, all the solutions when the volume does not exceed j, the attribute is Max.

Then just perform different state transitions directly according to different s[i].
(Here, the 01 backpack is regarded as a special multiple backpack, that is, s[i] is 1)

In addition, violence will time out, so binary optimization and multiple backpacks are required.

If it is helpful, please give a free like~ Someone watching is the motivation to support me to write down!

Disclaimer:
The source of the algorithm idea is Mr. Y. For details, please refer to https://www.acwing.com/
This article is only used for learning records and exchanges

Guess you like

Origin blog.csdn.net/SRestia/article/details/129731191