畅谈分组背包问题

简介: 畅谈分组背包问题

分组背包问题是背包问题的一种变体,它在一组物品中进行选择,每个物品属于某个特定的组。问题的描述通常是这样的:给定若干组物品,每组物品都有自己的重量、价值以及数量限制。目标是选择若干组物品放入背包中,使得背包中物品的总价值最大。

这里用acwing上的例题:9. 分组背包问题 - AcWing题库


朴素解法

这里朴素解法利用的二维数组f[i][j]来进行状态转移,枚举物品组数,枚举体积,枚举对于每组物品的决策,选还是不选,以得到最优解。这里朴素解法不再详细介绍,只放一个代码段,因为后面还可以优化一下。


其实看起来跟多重背包的朴素解法差不多,有什么不同的,下面放上了两段代码,比较看一下。不同在了就是在状态转移上了,多重背包呢可以选多个所以用k来控制,分组背包呢,例题中一组背包中最多只允许选一个,就是对于一组背包可以不选可以选一个。每一个物品都是不同的、有个性的,没有完全相同的,第三个for循环就是在枚举每一组具体的物品。


一维优化解法

对照朴素解法,多重背包呢时间复杂度那个for循环k的可以优化掉,空间复杂度也可以优化成一维的,但是时间复杂度优化是有条件的,多重背包呢可以组合进行二进制优化,也可以分类进行单调队列优化。分组背包呢,第i组物品的体积价值都是各不相同的,毫无规律可言,何以优化,但是在空间复杂度上可以优化成一维,f[i][j]是在f[i-1][j]转移过来的,就是在前一组物品决策完转移过来的,只是用了上一行的数据,有点类似01背包的一维优化。

#include<iostream>
using namespace std;
int dp[1005],v[1005],w[1005];//dp[i]表示背包容量为i时所获得最大价值
int N,V;
int main(){
  cin>>N>>V;
  int p;//p表示第p组物品
  for(int i=1;i<=N;i++){
    cin>>p;
    for(int j=1;j<=p;j++){
      cin>>v[j]>>w[j];
    }
        //因为dp[j]会先于dp[j-v[k]]更新,所以dp[j-v[k]]的值等价于dp[i-1][j-v[k]]
    for(int j=V;j>=1;j--){//逆序枚举背包容量
      for(int k=1;k<=p;k++){
        if(j>=v[k]){
          dp[j]=max(dp[j],dp[j-v[k]]+w[k]);
        }
      }
    }
  }
  cout<<dp[V]<<endl;
  return 0;
}

这里注意枚举背包容量和枚举k顺序不可颠倒,不然dp[j-v[k]]的值就不等价于dp[i-1][j-v[k]]了。


变式题型

小编做过其他类型的题,但都是分组背包的变式。有的题呢,一组物品给你限定了选多少个,比如选2个3个,例题中最多选一个,这样的话就比较麻烦了,既要确定选了哪一组物品又要达到选几个的要求,还是再次基础上,利用贪心,在每一组背包选几个的要求基础上,使得每一组背包都是最优的就可以(01背包)。用背包容量去枚举每一组背包,再去加一个if判断是否达到选几个的要求。有的呢还会物品会乱序输入,让你自己去分组好,再去进行选择。下面放一个我写过的题的代码,组数打乱自己找的(当然题中样例每打乱)。

#include<iostream>
#include<vector>
using namespace std;
int w[31],c[31];
int dp[201];
int v,n,p,t;
int main(){
  cin>>v>>n>>t;//v容量n物品t组数
  vector<vector<int>> group(t+1);
  for(int i=1;i<=n;i++){
    cin>>w[i]>>c[i]>>p;//p属于第几组
    group[p].push_back(i);//把下标往里抛就行
  }
  for(int i=1;i<=t;i++){//与一维优化类似
    for(int j=v;j>=0;j--){
      for(int k=0;k<group[i].size();k++){
        int index=group[i][k];
        if(j>=w[index]){
          dp[j]=max(dp[j],dp[j-w[index]]+c[index]);
        }
      }
    }
  }
  cout<<dp[v]<<endl;
  return 0;
}
/*
10 6 3
2 1 1
3 3 1
4 8 2
6 9 2
2 8 3
3 9 3
*/
//20

分组背包呢,听起来就是分组分组……,无非还是01背包的变形,背包问题呢,变形非常多,但是万变不离其宗,方法会了,其他变式也都迎刃而解。小编水平有限,能说的都在文章展现了,有错误的地方请大家指出,大家有疑问的地方随时可以私信我,看到必答。下篇更新有依赖的背包。

相关文章
|
测试技术
蓝桥杯2021年第十二届省赛真题-砝码称重(动态规划)
蓝桥杯2021年第十二届省赛真题-砝码称重(动态规划)
广东工业大学第十四届程序设计竞赛 1004免费送气球(线段树)
广东工业大学第十四届程序设计竞赛 1004免费送气球(线段树)
76 0
|
存储 机器学习/深度学习 算法
【蓝桥杯集训·每日一题】AcWing 4074. 铁路与公路
文章目录 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 三、知识风暴 Floyd 算法 Spfa 算法
103 0
|
Android开发
LeetCode 双周赛 98,脑筋急转弯转不过来!
大家好,我是小彭。 昨晚是 LeetCode 第 98 场双周赛,你参加了吗?这场周赛需要脑筋急转弯,转不过来 Medium 就会变成 Hard,转得过来就变成 Easy。
81 0
|
机器学习/深度学习 人工智能 算法
2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)G.希望(组合数学 bfs)
2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)G.希望(组合数学 bfs)
232 0
2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)G.希望(组合数学 bfs)
|
算法
2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)热身赛 B.这是一道大水题(树状数组)
2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)热身赛 B.这是一道大水题(树状数组)
156 0
2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)热身赛 B.这是一道大水题(树状数组)
|
机器学习/深度学习
2018NOIP集训-5 货物运输(倍增)
2018NOIP集训-5 货物运输(倍增)
94 0
2018NOIP集训-5 货物运输(倍增)
|
算法 BI vr&ar
【算法题解】2022河南萌新联赛第(三)场:河南大学
【算法题解】2022河南萌新联赛第(三)场:河南大学
【算法题解】2022河南萌新联赛第(三)场:河南大学
|
Shell 计算机视觉
2021年中国大学生程序设计竞赛女生专场C. 连锁商店(状压dp 思维 贪心)
2021年中国大学生程序设计竞赛女生专场C. 连锁商店(状压dp 思维 贪心)
150 0