【基础算法】 分组背包问题

249 阅读2分钟

🌹作者:云小逸
📝个人主页:云小逸的主页
📝Github:云小逸的Github
🤟motto:要敢于一个人默默的面对自己,==强大自己才是核心==。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前,其次就是现在!学会自己和解,与过去和解,努力爱自己。==希望春天来之前,我们一起面朝大海,春暖花开!==🤟 👏专栏:C++👏 👏专栏:Java语言👏👏专栏:Linux学习👏
👏专栏:C语言初阶👏👏专栏:数据结构👏👏专栏:备战蓝桥杯👏

@TOC


前言

今天我们继续学习算法,加油。这篇文章写的是分组背包问题,使用了Dp思想。希望这篇可以有幸帮助到你,码字不易,请多多支持。 在这里插入图片描述

——————————————————————————————

分组背包问题

问题描述

NN 组物品和一个容量为 VV 的背包,第 ii 组物品包含 SiS_i 个物品,第 jj 个物品的体积为 vi,jv_{i,j},价值为 wi,jw_{i,j}。每个物品只能选择一次,求解将哪些物品装入背包可以使这些物品的总体积不超过背包容量,且总价值最大。

输入格式

第一行有两个整数N,V,用空格隔开,分别表示物品组数和背包容量。 接下来有N组数据: 。每组数据第一行有一个整数S;,表示第i个物品组的物品数量; 。每组数据接下来有S;行,每行有两个整数 vi;, wu;i,用空格隔开,分别表示第i个物品组的第j个物品的体积和价值;

输出格式

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

数据范围

0<N,v≤ 100 0<S; ≤ 100 0<Uij , wij ≤100

输入样例

3 5
2
1 2
2 4
1
3 4
1
4 5

输出样例:

8

解法

分组背包问题可以看做是多个01背包问题的组合,与普通01背包不同的是,每组物品有多个可选元素,需要对每组物品进行选择。 由于物品的数量和价值都有可能很大,暴力枚举每个物品的选择状态是不可行的。因此,我们需要用动态规划的方法来解决此问题。 设 f[i][j]f[i][j] 表示在前 ii 组物品中选取总体积不超过 jj 的物品的最大价值,则我们有: f[i][j]=max0kSif[i1][jkt=1kvi,t]+kt=1kwi,tf[i][j] = \max_{0 \leq k \leq S_i} { f[i-1][j-k \sum_{t=1}^k v_{i,t}] + k \sum_{t=1}^k w_{i,t}} 其中,kk 表示选取第 ii 组物品的 kk 个物品,t=1kvi,t\sum_{t=1}^k v_{i,t} 表示这 kk 个物品的总体积,t=1kwi,t\sum_{t=1}^k w_{i,t} 表示这 kk 个物品的总价值。

代码:

#include <iostream>
#include <cstdio>
using namespace std;
int n, m;
int v[110][110], w[110][110], f[110], s[110];
int main() {
    scanf ("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++ ) {
        scanf ("%d", &s[i]);
        for (int j = 1; j <= s[i]; j ++ ) {
            scanf ("%d%d", &v[i][j], &w[i][j]);
        }
    }
    for (int i = 1; i <= n; i ++ ) {
        for (int j = m; j >= 1; j -- ) { //枚举所有体积
            for (int k = 1; k <= s[i]; k ++ ) { //枚举所有选择
                if(v[i][k] <= j) { //必须要满足,否则下面的下标减出来是负数
                    f[j] = max(f[j]/*不选*/, f[j - v[i][k]] + w[i][k]/*选*/);
                }
            }
        }    
    }
    printf("%d", f[m]);
    return 0;
}

时间复杂度

nn 个物品中,所有体积的最大值为 VmaxV_{max},则对于每个物品,需要枚举 2ki2^{k_i} 种情况,时间复杂度为 O(nVmax2kmax)O(nV_{max}2^{k_{max}}),其中 kmaxk_{max} 表示 kik_i 的最大值。由于 kmaxk_{max} 通常比较小,因此该算法的时间复杂度为 O(nVmax)O(nV_{max})

最后

十分感谢你可以耐着性子把它读完和我可以坚持写到这里,送几句话,对你,也对我:

1.把时间尺度拉长,拉长十年看当下

2.不说负面情绪,只描述事实;

3.越专注于过好自己,能量和幸运越会照顾你; 只解决问题,不做没有意义的担心,输了就认;

4.学会原谅自己,要允许自己做错事,允许自己出现情绪波动,我知道你已经很努力很努力在做好了

5.所有你害怕的、想逃避的事情,最终都要面对,既然这样不如选择坦然面对。即使结果不如人愿,没关系,至少这个过程是享受的,而不是一路带着恐惧和害怕。

最后如果觉得我写的还不错,请不要忘记==点赞==✌,==收藏==✌,加==关注==✌哦(。・ω・。)

愿我们一起加油,奔向更美好的未来,愿我们从懵懵懂懂的一枚==菜鸟==逐渐成为==大佬==。加油,为自己点赞!