多重背包 初学篇

来源:互联网 发布:maven 打包 java 工程 编辑:程序博客网 时间:2024/06/08 07:37

关于更多背包的内容可以在我的“背包”类别中查看

一、题目

有 n种物品和一个容量为 m 的背包。第 i 种物品最多有 num i 件可用,每件耗费的空间是 vi ,价值是 w i 。求解将哪些物品装入背包可使这些物品的耗费的空间总和不超过背包容量,且价值总和最大。

二、思路

跟01背包转向完全背包一样,这里的k只不过是有了范围我们依然可以直接开始遍历,相信看过了前两篇博客思路大家应该都有了,至于O(V N )的算法因为较难一点,我们我们就从二进制优化的方法开始说,这种方法大多数的题也都可以了

三、二进制优化

#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>using namespace std;const int N=1e6+1100;int v[N], w[N], num[N];int dp[N];int n,m;//01背包void ZeroOnePack(int v, int w){    for (int i = m; i >= v; i--)    {        dp[i] = max(dp[i], dp[i - v] + w);    }}//完全背包void CompletePack(int v, int w){    for (int i = v; i <= m; i++)    {        dp[i] = max(dp[i], dp[i - v] + w);    }}//多重背包void MultiplePack(int v, int w, int num){    if (v * num >= m)//如果总容量比这个物品的容量要小,那么这个物品可以直到取完,相当于完全背包    {        CompletePack(v, w);        return ;    }    else//否则就将多重背包转化为01背包    {        int k = 1;        while (k < num)        {            ZeroOnePack(k*v, k*w);            num -= k;            k *= 2;//这里采用二进制思想        }        ZeroOnePack(num*v, num*w);    }}int main(){    int t;    scanf("%d", &t);    while (t--)    {        scanf("%d%d", &n, &m);        for (int i = 1; i <= n; i++)            scanf("%d%d%d", &v[i], &w[i], &num[i]);        memset(dp, 0, sizeof(dp));        for (int i = 1; i <= n; i++)            MultiplePack(v[i], w[i], num[i]);        printf("%d\n", dp[m]);    }    return 0;}