混合背包(01,多重,完全)

题目描述

有 N 种物品和一个容量是 V 的背包。

物品一共有三类:
第一类物品只能用1次(01背包);
第二类物品可以用无限次(完全背包);
第三类物品最多只能用 si 次(多重背包);
每种体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。

输入

第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。
si=−1 表示第 i 种物品只能用1次;
si=0 表示第 i 种物品可以用无限次;

si>0 表示第 i 种物品可以使用 si 次;

数据范围
0 0 −1≤si≤1000

输出

输出一个整数,表示最大价值。

样例输入 Copy
4 5
1 2 -1
2 4 1
3 4 0
4 5 2
样例输出 Copy
8

每种不同的背包用不同的循环。其中多重背包直接循环超时(一层物品,二层背包容量,三层物品数量),用二进制优化时间同时转化为01背包问题

代码

#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
using namespace std;
int n, v, dp[1005], a[1005], b[1005], s[1005];
int main() {
    scanf("%d%d", &n, &v);
    for (int i = 0; i < n; i++)scanf("%d%d%d", &a[i], &b[i], &s[i]);
    for (int i = 0; i < n; i++) {
        if (s[i] == -1) {//01背包
            for (int j = v; j >= a[i]; j--)
                dp[j] = max(dp[j], dp[j - a[i]] + b[i]);
        }
        else if (s[i] == 0) {//完全bag
            for (int j = a[i]; j <= v; j++)
                dp[j] = max(dp[j], dp[j - a[i]] + b[i]);
        }
        else {//多重bag,二进制拆分提高速度(转化为01背包)
            //原理:所有数都能用二进制表示
            int wow = s[i], xa, xb;
            for (int k = 1;k <= wow;k *= 2) {
                xa = k * a[i];
                xb = k * b[i];
                for (int j = v;j >= xa;j--) 
                    dp[j] = max(dp[j], dp[j - xa] + xb);
                wow -= k;
            }//拆分还有剩余
            if (wow > 0) {
                xa = wow * a[i];
                xb = wow * b[i];
                for (int j = v; j >= xa; j--)
                    dp[j] = max(dp[j], dp[j - xa] + xb);
            }
        }
    }
    printf("%d\n", dp[v]);
    return 0;
}

你可能感兴趣的:(动态规划,算法)