每周一算法:背包问题(三)多重背包

多重背包

N N N件物品和一个容量是 M M M的背包。第 i i i种物品最多有 s i s_i si件,每件的体积是 v i v_i vi,价值是 w i w_i wi

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。

输出最大价值。

输入格式

第一行两个整数, N N N M M M,用空格隔开,分别表示物品数量和背包容积。

接下来有 N N N 行,每行三个整数 v i v_i vi, w i w_i wi, s i s_i si,用空格隔开,分别表示第 i i i 件物品的体积,价值和数量。

输出格式

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

样例 #1

样例输入 #1

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

样例输出 #1

10

提示

0 < N ≤ 1000 , 0 < M ≤ 2000 0<N≤1000,0<M\le2000 0<N1000,0<M2000

0 < v i , w i , s i ≤ 2000 0<v_i,w_i,s_i≤2000 0<vi,wi,si2000

算法思想

状态表示

多重背包的特点是第 i i i种物品最多有 s i s_i si件。仍可以采用01背包的思想,将处理每种物品作为一个阶段,考虑在不同背包容量情况下的最大价值,将其状态定义为 f [ i ] [ j ] f[i][j] f[i][j],表示对于 i i i种物品,在背包容量为 j j j的情况下,背包获得的最大价值。

状态计算

在当前阶段,对于第 i i i种物品来说,有多种情况可以选择:

  • 放入 0 0 0件,此时的最大价值为前 i − 1 i-1 i1种物品,在背包容量为 j j j的情况下的最大价值 f [ i − 1 ] [ j ] f[i-1][j] f[i1][j]
  • 放入 1 1 1件,此时背包的最大价值为前 i − 1 i-1 i1种物品,在背包容量为 j − v i j-v_i jvi的情况下的最大价值 f [ i − 1 ] [ j − v i ] + w i f[i-1][j-v_i]+w_i f[i1][jvi]+wi
  • 放入 2 2 2件,此时背包的最大价值为前 i − 1 i-1 i1种物品,在背包容量为 j − 2 × v i j-2\times v_i j2×vi的情况下的最大价值 f [ i − 1 ] [ j − 2 × v i ] + 2 × w i f[i-1][j-2\times v_i]+2\times w_i f[i1][j2×vi]+2×wi
  • 放入 k k k件,此时背包的最大价值为前 i − 1 i-1 i1种物品,在背包容量为 j − k × v i j-k\times v_i jk×vi的情况下的最大价值 f [ i − 1 ] [ j − k × v i ] + k × w i f[i-1][j-k\times v_i]+k\times w_i f[i1][jk×vi]+k×wi
  • 放入 s i s_i si件,此时背包的最大价值为前 i − 1 i-1 i1种物品,在背包容量为 j − s i × v i j-s_i\times v_i jsi×vi的情况下的最大价值 f [ i − 1 ] [ j − s i × v i ] + k × w i f[i-1][j-s_i\times v_i]+k\times w_i f[i1][jsi×vi]+k×wi

以上情况的前提是背包能够装得下 k k k件第 i i i种物品,也就是背包容量 j ≥ k × v i j\ge k\times v_i jk×vi。那么, f [ i ] [ j ] f[i][j] f[i][j]应该选择所有情况的最大值,即 f [ i ] [ j ] = max ⁡ { f [ i − 1 ] [ j − k × v i ] + k × w i } f[i][j] = \max\{f[i-1][j-k\times v_i]+k\times w_i\} f[i][j]=max{f[i1][jk×vi]+k×wi},其中 0 ≤ k ≤ s i 0\le k\le s_i 0ksi,并且 k × v i ≤ j k\times v_i \le j k×vij

初始状态

f [ 0 ] [ 0 ] f[0][0] f[0][0]表示将前 0 0 0种物品装入容量为 0 0 0的背包中的产生的最大价值为 0 0 0

时间复杂度

  • 状态数 n × m n\times m n×m
  • 状态计算时需要枚举第 i i i件物品的数量 s i s_i si,时间复杂度为 O ( s i ) O(s_i) O(si)

总的时间复杂的为 O ( n × m × s ) O(n\times m\times s) O(n×m×s)

代码实现

#include <iostream>
using namespace std;
const int N = 1010, M = 2010;
int f[N][N];
int main(){int n, m;cin >> n >> m;for(int i = 1; i <= n; i++){int v, w, s;cin >> v >> w >> s;for(int j = 0; j <= m; j++){for(int k = 0; k <= s && k * v <= j; k++){f[i][j] = max(f[i][j], f[i - 1][j - k * v] + k * w);}}}cout<<f[n][m]<<endl;return 0;
}

算法优化

根据上述状态转移方程,考虑能否像完全背包一样的思路进行优化呢?

f [ i ] [ j ] = max ⁡ { f [ i − 1 ] [ j ] , f [ i − 1 ] [ j − v ] + w , f [ i − 1 ] [ j − 2 × v ] + 2 × w + . . . + f [ i − 1 ] [ j − s × v ] + s × w } f[i][j] = \max\{f[i-1][j], f[i-1][j-v]+w, f[i-1][j-2\times v]+2\times w+...+f[i-1][j-s\times v]+s\times w\} f[i][j]=max{f[i1][j],f[i1][jv]+w,f[i1][j2×v]+2×w+...+f[i1][js×v]+s×w}

可得, f [ i ] [ j − v ] = max ⁡ { f [ i − 1 ] [ j − v ] , f [ i − 1 ] [ j − 2 × v ] + w , f [ i − 1 ] [ j − 3 × v ] + 2 × w + . . . + f [ i − 1 ] [ j − ( s + 1 ) × v ] + ( s + 1 ) × w } f[i][j - v] = \max\{f[i-1][j - v], f[i-1][j-2\times v]+w, f[i-1][j-3\times v]+2\times w+...+f[i-1][j-(s+1)\times v]+(s+1)\times w\} f[i][jv]=max{f[i1][jv],f[i1][j2×v]+w,f[i1][j3×v]+2×w+...+f[i1][j(s+1)×v]+(s+1)×w}

f [ i ] [ j − v ] f[i][j - v] f[i][jv] f [ i ] [ j ] f[i][j] f[i][j]和对比可以发现,多了一项 f [ i − 1 ] [ j − ( s + 1 ) × v ] + ( s + 1 ) × w f[i-1][j-(s+1)\times v]+(s+1)\times w f[i1][j(s+1)×v]+(s+1)×w。如果计算出 f [ i ] [ j − v ] f[i][j - v] f[i][jv],那么是否能得到 f [ i ] [ j ] f[i][j] f[i][j]呢?举个栗子:

在这里插入图片描述

也就是说,知道前 s + 1 s+1 s+1项的最大值并不能计算出前 s s s项的最大值,因此不能采用完全背包的思想来优化多重背包。

二进制枚举

在计算状态的过程中,需要枚举第 i i i种物品的数量 [ 0 , s i ] [0,s_i] [0,si],这里采用一种更高效的枚举方式——二进制枚举。例如当 s i = 1023 s_i=1023 si=1023时,可以将第 i i i种物品“打包”为:

  • 0 0 0件一组
  • 1 1 1件一组
  • 2 2 2件一组
  • 4 4 4件一组
  • 512 512 512件一组

通过上述组与组之间的组合,可以表示出 [ 0 , 1023 ] [0,1023] [0,1023]之间的任意一个数。如果把每组物品看成是01背包中的一种物品(仅能选择一次),那么就相当于用 10 10 10个新物品来表示原来的第 i i i个物品,通过组合这 10 10 10个新物品就可以枚举出第 i i i个物品的全部方案。

时间复杂度

  • 状态数 n × m n\times m n×m
  • 通过上述思想,原来要枚举 s s s次,现在只需要枚举 l o g s logs logs

总的时间复杂的为 ( n × m × l o g s ) (n\times m\times logs) (n×m×logs)

代码实现

#include <iostream>
using namespace std;
const int N = 1010 * 12, M = 2010;
int v[N], w[N];
int f[M];
int main()
{int n, m, k = 0;cin >> n >> m;for(int i = 1; i <= n; i ++){int a, b, s;cin >> a >> b >> s;//二进制拆分for(int j = 1; j <= s; j *= 2){v[++ k] = j * a;w[k] = j * b;s -= j;}//拆分后还有剩余if(s) v[++ k] = s * a, w[k] = s * b;}n = k; //拆分后实际的物品数量//01背包for(int i = 1; i <= n; i ++)for(int j = m; j >= v[i]; j --)f[j] = max(f[j], f[j - v[i]] + w[i]);cout << f[m];return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/195021.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

日常巡检脚本-2

#!/bin/bash# 检查系统负载 load$(awk {print $1} /proc/loadavg) cores$(grep -c ^processor /proc/cpuinfo) load_threshold$(echo "scale2; $cores * 0.7" | bc) if [ "$(echo "$load > $load_threshold" | bc)" -ne 0 ]; thenecho "…

浅谈什么是语音芯片的白噪音支持功能:打造舒适家居与优质音频体验

随着科技的不断进步和人们对生活质量要求的提升&#xff0c;语音芯片已经成为了现代电子产品中不可或缺的一部分。而在这些语音芯片中&#xff0c;支持白噪音的功能逐渐受到人们的关注。本文将围绕语音芯片中的白噪音支持功能展开讨论&#xff0c;带您领略其带来的舒适家居与优…

最强Node js 后端框架学习看这一篇文章就够

距离上次认真花时间写作&#xff0c;似乎已经过了许久许久&#xff0c;前端讲了一个新框架 &#xff0c;叫 Nest.js 下方是课件&#xff0c;有过一定开发经验可跟随视频学习 B站 地址 &#xff1a; https://www.bilibili.com/video/BV1Lg4y197u1/?vd_sourcead427ffaf8a5c8344…

Linux --- 进程控制

目录 1. 进程创建 1.1. 内核数据结构的处理 1.2. 代码的处理 1.3. 数据的处理&#xff1a; 方案一&#xff1a;fork创建子进程的时候&#xff0c;直接对数据进行拷贝处理&#xff0c;让父子进程各自私有一份 方案二&#xff1a;写实拷贝(copy on write) 1.4. fork常规用…

精通Nginx(21)-大幅度提升性能优化方法

无论何种类型的服务器或应用,其性能都取决于许多可变项,包括但不限于物理硬件、操作系统、数据库、应用服务器等中间件、应用结构等。性能优化通常在碰到性能瓶颈时才进行调优测试,确定瓶颈,改进限制,并不断重复,直至满足性能需求。 本文仅针对Nginx作为一个中间…

18本书让你从现代骗局中醒来

下面十八本书籍可以让你从受限的上下文骗局中脱身&#xff0c;或者至少能意识到&#xff1a; 1、《Be Here Now》Ram Dass&#xff1a; 是 1971 年出版的一本关于灵性、瑜伽和冥想的书&#xff0c;作者是美国瑜伽士兼灵性导师拉姆达斯&#xff08;Ram Dass&#xff0c;原名理查…

后端Long型数据传到前端js后精度丢失的问题

假设一个场景&#xff0c;MybatisPlus的雪花算法生成long类型主键ID&#xff0c;存入数据库&#xff0c;前端获取到数据后&#xff0c;要执行一个更新操作&#xff08;updateById&#xff09;&#xff0c;但这时会出现无法成功更新的情况&#xff01;这是因为前端在长度大于17位…

24.Python 网络编程之socket编程

目录 1.认识TCP/IP2.socket编程2.1 使用socket2.2 使用socketserver 1.认识TCP/IP 计算机网络就是把各个计算机连接在一起&#xff0c;在网络中的计算机可以互相通信。 网络编程是如何在程序中实现两台计算机的通信。 网络通信是两台计算机上的两个进程之间的通信。 为了把…

DevOps|研发提效-敏捷开发之每日站立会

对于研发效能团队建设和组织&#xff0c;本文不再赘述&#xff0c;可以参考之前的文章&#xff0c;已经讲得很透彻了。本文重点讲我们日常是怎么开站立会&#xff0c;怎么让团队跑起来&#xff0c;高效能产出的。每日站立会&#xff0c;15分钟到30分钟&#xff0c;看似非常短的…

【编码魔法师系列_构建型1.3 】抽象工厂模式(Abstract Factory)

学会设计模式&#xff0c;你就可以像拥有魔法一样&#xff0c;在开发过程中解决一些复杂的问题。设计模式是由经验丰富的开发者们&#xff08;GoF&#xff09;凝聚出来的最佳实践&#xff0c;可以提高代码的可读性、可维护性和可重用性&#xff0c;从而让我们的开发效率更高。通…

数字信号处理_第4个编程实例(信号的采样与重建)

配套的讲解视频详见数字信号处理14-1_模拟信号转换至数字信号的过程_哔哩哔哩_bilibili&#xff0c;数字信号处理14-2_冲激串的傅里叶变换及采样过程的时频域表示_哔哩哔哩_bilibili&#xff0c;数字信号处理14-3_信号重建与采样定理及Matlab编程实例_哔哩哔哩_bilibili %% //…

Linux常用命令——atq命令

在线Linux命令查询工具 atq 列出当前用户的at任务列表 补充说明 atq命令显示系统中待执行的任务列表&#xff0c;也就是列出当前用户的at任务列表。 语法 atq(选项)选项 -V&#xff1a;显示版本号&#xff1b; -q&#xff1a;查询指定队列的任务。实例 at now 10 minu…

一个完整的手工构建的cuda动态链接库工程 03记

1&#xff0c; 源代码 仅仅是加入了模板函数和对应的 .cuh文件&#xff0c;当前的目录结构如下&#xff1a; icmm/gpu/add.cu #include <stdio.h> #include <cuda_runtime.h>#include "inc/add.cuh"// different name in this level for different type…

pygame时序模块time

文章目录 简介时钟对象平抛运动 pygame系列&#xff1a;初步&#x1f48e;加载图像&#x1f48e;图像变换&#x1f48e;直线绘制 简介 之前在更新图形的时候&#xff0c;为了调控死循环的响应时间&#xff0c;用到了time.sleep。而实际上&#xff0c;我们并不需要额外导入其他…

LeetCode二分查找:寻找比目标字母大的最小字母

LeetCode二分查找&#xff1a;寻找比目标字母大的最小字母 题目描述 给你一个字符数组 letters&#xff0c;该数组按非递减顺序排序&#xff0c;以及一个字符 target。letters 里至少有两个不同的字符。 返回 letters 中大于 target 的最小的字符。如果不存在这样的字符&…

Failed to connect to gitee.com port 443: Time out 连接超时提示【Bug已完美解决-鸿蒙开发】

文章目录 项目场景:问题描述原因分析:解决方案:解决方案1解决方案2:解决方案3:此Bug解决方案总结解决方案总结**心得体会:解决连接超时问题的三种方案**项目场景: 导入Sample时遇到导入失败的情况,并提示“Failed to connect to gitee.com port 443: Time out”连接超…

YouTube Premium 会员白嫖教程

前言 YouTube是美国Alphabet旗下的视频分享网站&#xff0c;也是目前全球最大的视频搜索和分享平台&#xff0c;同时允许用户上传、观看、分享及评论视频 1、点击自己的头像&#xff0c;点击购买内容与会员 2、点击免费试订 3、这里选择个人 4、点击开始试用一个月 5、添加一…

Git 配置文件(.gitignore)

前言 在使用 Git 分布式版本控制系统的时候&#xff0c;有些文件如&#xff1a;数据库的一些配置文件&#xff0c;我们不想让这类文件在远程仓库让 Git 来管理&#xff0c;不想让别人看到&#xff0c;此时就可以自己在 Git 仓库目录下创建 / 在远程仓库创建的时候就配置好 .git…

计算机网络扫盲(3)——网络核心

一、概述 在之前的文章中&#xff0c;我们已经介绍了计算机网络的边缘&#xff0c;本文我们将继续介绍网络核心部分&#xff0c;即由互联因特网系统的分组交换机和链路构成的网状网络。 二、分组交换 在各种网络应用中&#xff0c;端系统彼此交换报文&#xff08;message)。报…

Java内存缓存神器:Caffeine(咖啡因)

文章目录 一、Caffeine简介二、缓存加载1、手动加载2、自动加载3、手动异步加载&#xff08;需要额外的包&#xff09;4、自动异步加载 三、缓存清理1、基于容量2、基于时间3、基于引用 四、缓存移出1、手动移出2、移出监听器 五、刷新缓存 一、Caffeine简介 官网&#xff1a;…