01背包 完全背包 多重背包 实现

01背包 完全背包 多重背包 实现
01背包

//O(NV)
f[0][0 ~ V] = 0;
for(int i = 1; i <= n; ++i)
    for(int j = 0; j <= V; ++j)
        if(j < w[i]) f[i][j] = f[i - 1][j];
        else f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + v[i]);

//O(NV) 滚动数组
f[0 ~ V] = 0;
for(int i = 1; i <= n; ++i)
    for(int j = V; j >= w[i]; --j)
        f[j] = max(f[j], f[j - w[i]] + v[i]);

完全背包

//O(NVK)
f[0][0 ~ V] = 0;
for(int i = 1; i <= n; ++i)
    for(int j = 0; j <= V; ++j)
        for(int k = 0; k * w[i] <= j; ++k)
            f[i][j] = max(f[i][j], f[i - 1][j - k * w[i]] + k * v[i]);//01背包思路

//O(NV)
f[0][0 ~ V] = 0;
for(int i = 1; i <= n; ++i)
    for(int j = 0; j <= V; ++j)
        if(j < w[i]) f[i][j] = f[i - 1][j];
        else f[i][j] = max(f[i - 1][j], f[i][j - w[i]] + v[i]);//顺序是正的

//O(NV) 滚动数组
f[0 ~ V] = 0;
for(int i = 1; i <= n; ++i)
    for(int j = w[i]; j <= V; ++j)
        f[j] = max(f[j], f[j - w[i]] + v[i]);

多重背包

二进制优化

//O(NVlogK)
f[0 ~ V] = 0;
for(int i = 1; i <= n; ++i){
    int num = c[i];
    for(int k = 1; num > 0; k <<= 1){
        int mul = min(k, num);
        for(int j = V; mul * w[i] <= j; --j){
            f[i] = max(f[j], f[j - mul * w[i]] + mul * v[i])
        }
    }
}


#include <iostream>
using namespace std;
 
/* 多重背包 二进制拆分
 * Time Complexity  大于O(N*V)
 * Space Complexity O(N*V)
 * 设 V <= 200 N <= 10 ,拆分后 物品总数 < 50
 * 每件物品有 log n[i]种状态
 */
 
int maxV[201];
int weight[50]; /* 记录拆分后物体重量 */
int value[50];  /* 记录拆分后物体价值 */
int V, N;
 
void main()
{
    int i, j;
    scanf("%d %d",&V, &N);
    int weig, val, num;
    int count = 0;
 
    for(i = 0; i < N; ++i)
    {
        scanf("%d %d %d",&weig,&val,&num);
 
        for(j = 1; j <= num; j <= 1) // 二进制拆分
        {
            weight[count] = j * weig;
            value[count++] = j * val;
            num -= j;
        }
        if(num > 0)//这里是剩余的
        {
            weight[count] = num * weig;
            value[count++] = num * val;
        }
    }
    for(i = 0; i < count; ++i)  // 使用01背包
    {
        for(j = V; j >= weight[i]; --j)
        {
            int tmp = maxV[j-weight[i]] + value[i];
            maxV[j] = maxV[j] > tmp ? maxV[j] : tmp;
        }
    }
    printf("%d",maxV[V]);
}

单调队列优化

int Q[V], f[2][V]; //单调队列,滚动数组

int z = 0;
memset(f[z], 0, sizeof f[z]);
f[z][0] = 0;
for(int i = 1; i <= n; ++i) {
    memset(f[!z], 0, sizeof f[!z]);
    for(int r = 0; r < w[i]; ++r) {
        int L = 0, R = 0;
        for(int p = 0; p * w[i] + r <= V; ++p) {
            while(L < R && f[z][Q[R - 1] * w[i] + r] - Q[R - 1] * v[i]
                    <= f[z][p * w[i] + r] - p * v[i]) --R;
            Q[R++] = p;
            while(L < R && p - c[i] > Q[L]) ++L;
            int q = Q[L];
            f[!z][p * w[i] + r] = (f[z][q * w[i] + r] - q * v[i]) + p * v[i];
        }
    }
    z = !z;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值