背包问题——分组背包

分组背包

1.定义

分组背包,通俗的讲就是,给你N组物品,然后每一组你至多选择一个物品(也可以不选),每个物品都有自己的体积和价值,现在给你一个容里为M的背包,让你用这个背包装物品,使得物品价值总和最大.

2.讲解

其实就类似于01背包,对于一个物品有两种决策选或不选,但是分组背包是在01背包的基础上对物品进行了分组,并且每一组只能最多选择一个物品,所以我们不妨用01背包的思想去思考分组背包.

分析:我们设f[i][j]为当前考虑到了第i组物品,剩余容里为j的背包能装物品的最大价值,那么很容易想到我们需要去枚举第i组物品,考虑选哪一个物品时最优的(或者不选),状态转移方程就是i f ( j > = v [ i ] [ k ] ) f [ i ] [ j ] = m a x ( f [ i ] [ j ] , f [ i − 1 ] [ j − v [ i ] [ k ] ] + w [ i ] [ k ] ),v[i][k]和w[i][k]分别表示第i组物品中第k个物品的体积和价值

代码:

for(int i=1;i<=n;i++)
     for(int j=0;j<=m;j++)
      for(int k=1;k<=s[i];k++)//s[i]表示第i组物品的个数
       if(j>=v[i][k])//剩余的背包容量j大于第i组的第k个物品的体积 
       {
             f[i][j] = max(f[i][j],f[i-1][j-v[i][k]]+w[i][k]);
       }

这里我们还可以对空间进行优化,我们可以观察到,f[i][…]只会用到f[i-1][…]的值,所以数组的第一维的空间完全可以用滚动数组的方式处理掉,但是如何不影响状态转移呢,我们来看滚掉之后的状态转移方程,

f[j] = max(f[j],f[j-v[i][k]]+w[i][k]);

 

这里的max里面的f [ j ] 和 f [ j − v [ i ] [ k ] ] 其实是f [ i − 1 ] [ j ] 和 f [ i − 1 ] [ j − v [ i ] [ k ] ],而不是f [ i ] [ j ] 和 f [ i ] [ j − v [ i ] [ k ] ],所以我们需要对体积的遍历做一些修改,从大到小循环,如果还是从小到大循环的话,那么这里的f [ j ] 和 f [ j − v [ i ] [ k ] ] 的含义就有可能是f [ i ] [ j ] 和 f [ i ] [ j − v [ i ] [ k ] ],而不是我们需要的f [ i − 1 ] [ j ] 和 f [ i − 1 ] [ j − v [ i ] [ k ] ],可以模拟一下就明白了,只靠想的话有点抽象.

5743: 分组背包

 

#include<bits/stdc++.h>
using namespace std;
long long int dp[1005];
vector<int> w[40];
vector<int> v[40];
int n,m,t; //n个物品,m容量,t组 
int main()
{
    cin>>m>>n>>t;
    for(int i=1;i<=n;i++)
    {
        int wi,vi,ti;
        cin>>wi>>vi>>ti;
        w[ti].push_back(wi);
        v[ti].push_back(vi);
    } 
    for(int i=1;i<=t;i++)
    {
        for(int j=m;j>=0;j--)
        {
            for(int k=0;k<w[i].size();k++)
            {
                if(j>=w[i][k])
                dp[j] = max(dp[j],dp[j-w[i][k]]+v[i][k]);
            }
        }
    }
    cout<<dp[m];
     return 0;
}

 

posted @ 2022-11-29 17:31  CRt0729  阅读(97)  评论(0编辑  收藏  举报