各种背包模板
把这些背包弄成了模板,比较方便也容易理解
注:这些背包模板都是以函数形式, 每次调用都只解决一个物品。
1.0/1背包
void _0_1bb (int m, int c, int v){//m:背包容量, c:此物品价值, v:此物品体积
for (int j = m; j >= v; j--){
dp[j] = max (dp[j], dp[j - v] + c);
}
}
完全背包
void wqbb (int m, int c, int v){//m:背包容量, c:此物品价值, v:此物品体积
for (int j = v; j <= m; j++){
dp[j] = max (dp[j], dp[j - v] + c);
}
}
多重背包
普通方法
void dcbb (int m, int c, int v, int num){//m:背包容量, c:此物品价值, v:此物品体积 num:此物品数量
for (int j = m; j >= v; j--){
for (int i = 1; i <= n; i++){
if (v * i > j){
break;
}
dp[j] = max (dp[j], dp[j - v * i] + c * i);
}
}
}
二进制方法
void dcbb (int m, int c, int v, int num){//m:背包容量, c:此物品价值, v:此物品体积 num:此物品数量
int tot = 0;
for (int j = 1; j <= num; j <<= 1){
sv[++tot] = v * j;
sc[++tot] = c * j;
num -= j;
}
if (num > 0){
sv[++tot] = num * v;
sc[++tot] = num * c;
}
for (int i = 1; i <= tot; i++){
for (int j = m; j >= sv[i]; j--){
dp[j] = max (dp[j], dp[j - sv[i]] + sc[i]);
}
}
}
单调队列优化
void dcbb (int m, int c, int v, int num){
for (int u = 0; u < v; u++){
int l = (m - u) / v;
int h = 0, t = 0;
s[t++] = make_pair (dp[u], 0);
for (int i = 1; i <= l; i++){
while (s[h].second < i - num){
h++;
}
while (s[t - 1].first <= dp[i * v + u] - i * c && t > h){
t--;
}
s[t++] = make_pair (dp[i * v + u] - i * c, i);
dp[i * v + u] = s[h].first + i * c;
}
}
}
分组背包
void fzbb (int m, int num){
for (int i = m; i >= 0; i--){
for (int j = 1; j <= num; j++){
if (v[j] > i){
continue;
}
dp[i] = max (dp[i], dp[i - v[j]] + c[j]);
}
}
}
二维费用背包
0/1
void _0_1fzbb (int M, int V, int v, int m, int c){
for (int i = V; i >= v; i --){
for (int j = M; j >= m; j--){
dp[i][j]= max (dp[i][j], dp[i - v][j - m] + c);
}
}
}
完全
void wqfzbb (int M, int V, int v, int m, int c){
for (int i = V; i >= v; i --){
for (int j = M; j >= m; j--){
dp[i][j]= max (dp[i][j], dp[i - v][j - m] + c);
}
}
}
多重
void dcbb (int M, int V, int c, int m, int v, int num){
int tot = 0;
for (int j = 1; j <= num; j <<= 1){
sv[++tot] = v * j;
sc[++tot] = c * j;
sm[++tot] = m * j
num -= j;
}
if (num > 0){
sv[++tot] = num * v;
sc[++tot] = num * c;
sm[++tot] = num * m;
}
for (int i = 1; i <= tot; i++){
for (int j = M; j >= sm[i]; j--){
for (int k = V; k >= sv[i]; k--)
dp[j][k] = max (dp[j][k], dp[j - sm[i]][k - sv[i]] + sc[i]);
}
}
}
注:这些模板可能是假的可能有些许小问题, 发现请及时指出
使用范例(单调队列优化的多重背包, 其他函数同理)
代码:
#include
#include
using namespace std;
#define MAXN 1000
int dp[MAXN + 5];
pair s[MAXN + 5];
void dcbb(int m, int c, int v, int num) {
for (int u = 0; u < v; u++) {
int l = (m - u) / v;
int h = 0, t = 0;
s[t++] = make_pair(dp[u], 0);
for (int i = 1; i <= l; i++) {
while (s[h].second < i - num) {
h++;
}
while (s[t - 1].first <= dp[i * v + u] - i * c && t > h) {
t--;
}
s[t++] = make_pair(dp[i * v + u] - i * c, i);
dp[i * v + u] = s[h].first + i * c;
}
}
}
int main() {
int n, m;
scanf("%d %d", &m, &n);
for (int i = 1; i <= n; i++) {
int v, c, num;
scanf("%d %d %d", &v, &c, &num);
dcbb(m, c, v, num);
}
printf("%d", dp[m]);
}