当前位置: 首页 > article >正文

算法【分组背包】

分组背包是指多个物品分组,每组只能取1件。每一组的物品都可能性展开就可以了。注意时间复杂度不会升阶,O(物品数量 * 背包容量)。

下面通过题目加深理解。

题目一

测试链接:通天之分组背包 - 洛谷

分析:这道题是分组背包的模板,对每个分组进行可能性的展开即不取这个分组和取这个分组的每一个能取的物品。下面代码采用记忆化搜索,严格位置依赖和空间压缩的解法不再赘述。代码如下。

#include <iostream>
#include <vector>
using namespace std;
int m, n;
int number_of_group = 0;
vector<vector<int>> group;
int data[1000][2];
int dp[100][1001];
int f(int groups, int weight){
    if(groups == number_of_group){
        return 0;
    }
    if(dp[groups][weight] != -1){
        return dp[groups][weight];
    }
    int ans = f(groups+1, weight);
    int nums = group[groups].size();
    for(int i = 0;i < nums;++i){
        if(weight - data[group[groups][i]][0] >= 0){
            ans = ans > f(groups+1, weight - data[group[groups][i]][0]) + data[group[groups][i]][1] ?
            ans : f(groups+1, weight - data[group[groups][i]][0]) + data[group[groups][i]][1];
        }
    }
    dp[groups][weight] = ans;
    return ans;
}
int main(void){
    int a_i, b_i, c_i;
    scanf("%d%d", &m, &n);
    vector<int> temp;
    for(int i = 0;i <= 99;++i){
        group.push_back(temp);
    }
    for(int i = 0;i < n;++i){
        scanf("%d%d%d", &a_i, &b_i, &c_i);
        data[i][0] = a_i;
        data[i][1] = b_i;
        group[c_i].push_back(i);
        number_of_group = number_of_group > c_i ?
        number_of_group : c_i;
    }
    ++number_of_group;
    for(int i = 0;i <= number_of_group-1;++i){
        for(int j = 0;j <= m;++j){
            dp[i][j] = -1;
        }
    }
    printf("%d", f(0, m));
    return 0;
}

其中,f函数返回在从组数为groups的组开始,剩余重量为weight的情况下的最大值。

题目二

测试链接:2218. 从栈中取出 K 个硬币的最大面值和 - 力扣(LeetCode)

分析:对于这道题,可以将每个栈看为一个分组,对每个分组进行可能性的展开,也就是不取这个栈和取1次、2次、3次......直到剩余次数和栈的硬币数的最小值。代码采用记忆化搜索,改成严格位置依赖和空间压缩的解法不再赘述。代码如下。

class Solution {
public:
    int dp[1000][2001];
    int f(int index, int times, vector<vector<int>>& piles){
        if(index == piles.size()){
            return 0;
        }
        if(dp[index][times] != -1){
            return dp[index][times];
        }
        int ans = f(index+1, times, piles);
        int length = piles[index].size();
        int sum = 0;
        for(int i = 0;i < length && i+1 <= times;++i){
            sum += piles[index][i];
            ans = ans > f(index+1, times-i-1, piles) + sum ?
            ans : f(index+1, times-i-1, piles) + sum;
        }
        dp[index][times] = ans;
        return ans;
    }
    int maxValueOfCoins(vector<vector<int>>& piles, int k) {
        for(int i = 0;i < 1000;++i){
            for(int j = 0;j < 2001;++j){
                dp[i][j] = -1;
            }
        }
        return f(0, k, piles);
    }
};

其中,f方法返回在从下标index的栈开始取,剩余次数为times的情况下,得到的最大值。


http://www.kler.cn/a/527178.html

相关文章:

  • 窥探目标文件
  • DeepSeek介绍
  • C++ 堆栈分配的区别
  • 雅思写作(支持句)
  • 论文阅读(七):贝叶斯因果表型网络解释遗传变异和生物学知识
  • springboot使用rabbitmq
  • 鸿蒙开发在onPageShow中数据加载不完整的问题分析与解决
  • 线段树(Segment Tree)和树状数组
  • FFmpeg(7.1版本)在Ubuntu18.04上的编译
  • 【二叉搜索树】
  • 2025-1-28-sklearn学习(47) (48) 万家灯火亮年至,一声烟花开新来。
  • Linux网络编程中的零拷贝:提升性能的秘密武器
  • 【PLL】参考杂散计算example
  • C++ 中的类(class)和对象(object)
  • P11467 网瘾竞赛篇之 generals 大法好
  • Java中的线程池参数(详解)
  • Python 学习进阶技术文档
  • Keepalived高可用集群入门学习
  • electron 应用开发实践
  • Android逆向(Mitmproxy)
  • 【自学笔记】JavaWeb的重点知识点-持续更新
  • Oracle11g数据库安装及建库教程
  • JavaScript 创建对象的8种方式?
  • Git进阶之旅:tag 标签 IDEA 整合 Git
  • 算法总结-数组/字符串
  • Linux 五种IO模型总篇(阻塞IO、非阻塞IO、信号驱动IO、多路复用IO(select、poll、epoll)、异步IO)