完全背包总结二

1.完全背包和0/1背包的区别?

完全背包的物体有无限个,可以多次放入

0/1背包的物体只有一个,只能放入一次

2.关于物品遍历顺序

在0/1背包中为了防止物品被重复放入,所以选择倒序遍历背包

而完全背包中,可以重复放入,所以选择正序遍历背包

具体来说,如题目

重量价值
物品1115
物品2320
物品3535

求大小为4的背包可获得的最大价值。

(1)对于0/1背包来说:各个物品只能放入一次

package other;import java.util.Arrays;
import java.util.Objects;public class Bag {public static void main(String[] args) {int[] weight=new int[]{1,3,4};int[] values=new int[]{15,20,30};Bag obj=new Bag();System.out.println("result: "+ obj.simpleBag2(weight,values,4));}public int simpleBag2(int[] weight,int[] values,int bag){int dp[]=new int[bag+1];//初始化Arrays.fill(dp,0);//双层for循环for(int i=0;i<weight.length;i++){//遍历物品for(int j=bag;j>=0;j--){//遍历背包System.out.println("拿起物品i="+i+"  ,\t重量:"+weight[i]+"\t背包容量:"+j);if(weight[i]<=j){dp[j]=Math.max(dp[j],dp[j-weight[i]]+values[i]);System.out.println("放入物品i="+i+"  ,\t价值:"+values[i]);} else {dp[j]=dp[j];System.out.println("不放入物品i="+i);}printArr(j,dp);}}printArr(null,dp);return dp[dp.length-1];}public void printArr(Integer j,int []arr){if(!Objects.isNull(j)){System.out.print("j = "+j+"  :\t\t");}for(int i=0;i<arr.length;i++){System.out.print(arr[i]+"\t");}System.out.println();}
}

拿起物品i=0  ,    重量:1    背包容量:4
放入物品i=0  ,    价值:15
j = 4  :        0    0    0    0    15    
拿起物品i=0  ,    重量:1    背包容量:3
放入物品i=0  ,    价值:15
j = 3  :        0    0    0    15    15    
拿起物品i=0  ,    重量:1    背包容量:2
放入物品i=0  ,    价值:15
j = 2  :        0    0    15    15    15    
拿起物品i=0  ,    重量:1    背包容量:1
放入物品i=0  ,    价值:15
j = 1  :        0    15    15    15    15    
拿起物品i=0  ,    重量:1    背包容量:0
不放入物品i=0
j = 0  :        0    15    15    15    15    
拿起物品i=1  ,    重量:3    背包容量:4
放入物品i=1  ,    价值:20
j = 4  :        0    15    15    15    35    
拿起物品i=1  ,    重量:3    背包容量:3
放入物品i=1  ,    价值:20
j = 3  :        0    15    15    20    35    
拿起物品i=1  ,    重量:3    背包容量:2
不放入物品i=1
j = 2  :        0    15    15    20    35    
拿起物品i=1  ,    重量:3    背包容量:1
不放入物品i=1
j = 1  :        0    15    15    20    35    
拿起物品i=1  ,    重量:3    背包容量:0
不放入物品i=1
j = 0  :        0    15    15    20    35    
拿起物品i=2  ,    重量:4    背包容量:4
放入物品i=2  ,    价值:30
j = 4  :        0    15    15    20    35    
拿起物品i=2  ,    重量:4    背包容量:3
不放入物品i=2
j = 3  :        0    15    15    20    35    
拿起物品i=2  ,    重量:4    背包容量:2
不放入物品i=2
j = 2  :        0    15    15    20    35    
拿起物品i=2  ,    重量:4    背包容量:1
不放入物品i=2
j = 1  :        0    15    15    20    35    
拿起物品i=2  ,    重量:4    背包容量:0
不放入物品i=2
j = 0  :        0    15    15    20    35    
0    15    15    20    35    
result: 35

可以观察到,由于dp[i]总是由前面的dp[i-1]推导来的,但是每次更新时,dp[i-1]没有物品的累积。

(2)对于完全背包来说:物品可以重复放入

package other;import java.util.Arrays;
import java.util.Objects;public class Bag {public static void main(String[] args) {int[] weight=new int[]{1,3,4};int[] values=new int[]{15,20,30};Bag obj=new Bag();System.out.println("result: "+ obj.simpleBag(weight,values,4));}public int simpleBag(int[] weight,int[] values,int bag){int dp[]=new int[bag+1];//初始化Arrays.fill(dp,0);//双层for循环for(int i=0;i<weight.length;i++){//遍历物品for(int j=1;j<=bag;j++){//遍历背包System.out.println("拿起物品i="+i+"  ,\t重量:"+weight[i]+"\t背包容量:"+j);if(weight[i]<=j){dp[j]=Math.max(dp[j],dp[j-weight[i]]+values[i]);System.out.println("放入物品i="+i+"  ,\t价值:"+values[i]);} else {dp[j]=dp[j];System.out.println("不放入物品i="+i);}printArr(j,dp);}}printArr(null,dp);return dp[dp.length-1];}public void printArr(Integer j,int []arr){if(!Objects.isNull(j)){System.out.print("j = "+j+"  :\t\t");}for(int i=0;i<arr.length;i++){System.out.print(arr[i]+"\t");}System.out.println();}
}

拿起物品i=0  ,    重量:1    背包容量:1
放入物品i=0  ,    价值:15
j = 1  :        0    15    0    0    0    
拿起物品i=0  ,    重量:1    背包容量:2
放入物品i=0  ,    价值:15
j = 2  :        0    15    30    0    0    
拿起物品i=0  ,    重量:1    背包容量:3
放入物品i=0  ,    价值:15
j = 3  :        0    15    30    45    0    
拿起物品i=0  ,    重量:1    背包容量:4
放入物品i=0  ,    价值:15
j = 4  :        0    15    30    45    60    
拿起物品i=1  ,    重量:3    背包容量:1
不放入物品i=1
j = 1  :        0    15    30    45    60    
拿起物品i=1  ,    重量:3    背包容量:2
不放入物品i=1
j = 2  :        0    15    30    45    60    
拿起物品i=1  ,    重量:3    背包容量:3
放入物品i=1  ,    价值:20
j = 3  :        0    15    30    45    60    
拿起物品i=1  ,    重量:3    背包容量:4
放入物品i=1  ,    价值:20
j = 4  :        0    15    30    45    60    
拿起物品i=2  ,    重量:4    背包容量:1
不放入物品i=2
j = 1  :        0    15    30    45    60    
拿起物品i=2  ,    重量:4    背包容量:2
不放入物品i=2
j = 2  :        0    15    30    45    60    
拿起物品i=2  ,    重量:4    背包容量:3
不放入物品i=2
j = 3  :        0    15    30    45    60    
拿起物品i=2  ,    重量:4    背包容量:4
放入物品i=2  ,    价值:30
j = 4  :        0    15    30    45    60    
0    15    30    45    60    
result: 60

可以观察到物品被重复放入

(3)对于0/1背包问题,双for循环顺序能否颠倒

尝试先背包后物品,是否会对结果有影响

public int simpleBag3(int[] weight,int[] values,int bag){int dp[]=new int[bag+1];//初始化Arrays.fill(dp,0);//双层for循环for(int j=bag;j>=0;j--){//遍历背包for(int i=0;i<weight.length;i++){//遍历物品System.out.println("拿起物品i="+i+"  ,\t重量:"+weight[i]+"\t背包容量:"+j);if(weight[i]<=j){dp[j]=Math.max(dp[j],dp[j-weight[i]]+values[i]);System.out.println("放入物品i="+i+"  ,\t价值:"+values[i]);} else {dp[j]=dp[j];System.out.println("不放入物品i="+i);}printArr(j,dp);}}printArr(null,dp);return dp[dp.length-1];}


拿起物品i=0  ,    重量:1    背包容量:4
放入物品i=0  ,    价值:15
j = 4  :        0    0    0    0    15    
拿起物品i=1  ,    重量:3    背包容量:4
放入物品i=1  ,    价值:20
j = 4  :        0    0    0    0    20    
拿起物品i=2  ,    重量:4    背包容量:4
放入物品i=2  ,    价值:30
j = 4  :        0    0    0    0    30    
拿起物品i=0  ,    重量:1    背包容量:3
放入物品i=0  ,    价值:15
j = 3  :        0    0    0    15    30    
拿起物品i=1  ,    重量:3    背包容量:3
放入物品i=1  ,    价值:20
j = 3  :        0    0    0    20    30    
拿起物品i=2  ,    重量:4    背包容量:3
不放入物品i=2
j = 3  :        0    0    0    20    30    
拿起物品i=0  ,    重量:1    背包容量:2
放入物品i=0  ,    价值:15
j = 2  :        0    0    15    20    30    
拿起物品i=1  ,    重量:3    背包容量:2
不放入物品i=1
j = 2  :        0    0    15    20    30    
拿起物品i=2  ,    重量:4    背包容量:2
不放入物品i=2
j = 2  :        0    0    15    20    30    
拿起物品i=0  ,    重量:1    背包容量:1
放入物品i=0  ,    价值:15
j = 1  :        0    15    15    20    30    
拿起物品i=1  ,    重量:3    背包容量:1
不放入物品i=1
j = 1  :        0    15    15    20    30    
拿起物品i=2  ,    重量:4    背包容量:1
不放入物品i=2
j = 1  :        0    15    15    20    30    
拿起物品i=0  ,    重量:1    背包容量:0
不放入物品i=0
j = 0  :        0    15    15    20    30    
拿起物品i=1  ,    重量:3    背包容量:0
不放入物品i=1
j = 0  :        0    15    15    20    30    
拿起物品i=2  ,    重量:4    背包容量:0
不放入物品i=2
j = 0  :        0    15    15    20    30    
0    15    15    20    30    
result: 30

为了保证物品只用一次,所以背包的遍历一定是倒序遍历,颠倒双for的遍历顺序是先背包后物品

保证了防止最合适的一个物品,由于左边的背包没有计算,所以无法累计物品的重量

最后只是选择了能放入了一个最合适的物品

所以这种方式是不可以的。

(4)对于完全背包问题,双for循环顺序能否颠倒

尝试先背包后物品,是否会对结果有影响

public int simpleBag4(int[] weight,int[] values,int bag){int dp[]=new int[bag+1];//初始化Arrays.fill(dp,0);//双层for循环for(int j=1;j<=bag;j++){//遍历背包for(int i=0;i<weight.length;i++){//遍历物品System.out.println("拿起物品i="+i+"  ,\t重量:"+weight[i]+"\t背包容量:"+j);if(weight[i]<=j){dp[j]=Math.max(dp[j],dp[j-weight[i]]+values[i]);System.out.println("放入物品i="+i+"  ,\t价值:"+values[i]);} else {dp[j]=dp[j];System.out.println("不放入物品i="+i);}printArr(j,dp);}}printArr(null,dp);return dp[dp.length-1];}
拿起物品i=0  ,	重量:1	背包容量:1
放入物品i=0  ,	价值:15
j = 1  :		0	15	0	0	0	
拿起物品i=1  ,	重量:3	背包容量:1
不放入物品i=1
j = 1  :		0	15	0	0	0	
拿起物品i=2  ,	重量:4	背包容量:1
不放入物品i=2
j = 1  :		0	15	0	0	0	
拿起物品i=0  ,	重量:1	背包容量:2
放入物品i=0  ,	价值:15
j = 2  :		0	15	30	0	0	
拿起物品i=1  ,	重量:3	背包容量:2
不放入物品i=1
j = 2  :		0	15	30	0	0	
拿起物品i=2  ,	重量:4	背包容量:2
不放入物品i=2
j = 2  :		0	15	30	0	0	
拿起物品i=0  ,	重量:1	背包容量:3
放入物品i=0  ,	价值:15
j = 3  :		0	15	30	45	0	
拿起物品i=1  ,	重量:3	背包容量:3
放入物品i=1  ,	价值:20
j = 3  :		0	15	30	45	0	
拿起物品i=2  ,	重量:4	背包容量:3
不放入物品i=2
j = 3  :		0	15	30	45	0	
拿起物品i=0  ,	重量:1	背包容量:4
放入物品i=0  ,	价值:15
j = 4  :		0	15	30	45	60	
拿起物品i=1  ,	重量:3	背包容量:4
放入物品i=1  ,	价值:20
j = 4  :		0	15	30	45	60	
拿起物品i=2  ,	重量:4	背包容量:4
放入物品i=2  ,	价值:30
j = 4  :		0	15	30	45	60	
0	15	30	45	60	
result: 60Process finished with exit code 0

所以,对于完全背包来说,只是更新的方式不一样,结果是一样的。

先物品后背包<=>行更新

先背包后物品<=>列更新

3.总结

0/1背包问题

        双for循环的的顺序不可以颠倒

        背包倒序遍历才能保证物品取用一次

完全背包问题

        双for循环顺序可以颠倒,只是更新是行更新还是列更新的问题

        背包正序,每个物品都可以取用无限次。

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

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

相关文章

Datax3.0+DataX-Web部署分布式可视化ETL系统

一、DataX 简介 DataX 是阿里云 DataWorks 数据集成的开源版本&#xff0c;主要就是用于实现数据间的离线同步。DataX 致力于实现包括关系型数据库&#xff08;MySQL、Oracle 等&#xff09;、HDFS、Hive、ODPS、HBase、FTP 等各种异构数据源&#xff08;即不同的数据库&#x…

找单身狗(C语言)

题目叙述&#xff1a; 一个数组中只有两个数字是出现一次&#xff0c;其他所有数字都出现了两次。 编写一个函数找出这两个只出现一次的数字。 例如&#xff1a; 数组的元素是&#xff1a;1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;1&#xff0c;…

从零开始手写mmo游戏从框架到爆炸(八)— byte数组传输

导航&#xff1a;从零开始手写mmo游戏从框架到爆炸&#xff08;零&#xff09;—— 导航-CSDN博客 Netty帧解码器 Netty中&#xff0c;提供了几个重要的可以直接使用的帧解码器。 LineBasedFrameDecoder 行分割帧解码器。适用场景&#xff1a;每个上层数据包&#xff0c;使…

Rust 初体验

Rust 初体验 安装 打开官网&#xff0c;下载 rustup-init.exe&#xff0c; 选择缺省模式&#xff08;1&#xff09;安装。 国内源设置 在 .Cargo 目录下新建 config 文件&#xff0c;添加如下内容&#xff1a; [source.crates-io] registry "https://github.com/rus…

spring-security SecurityContextHolder

翻译版本【spring-security 6.2.1】SecurityContextHolder SecurityContextHolder Spring Security身份验证模型的核心是SecurityContextHolder。它包含SecurityContext。 SecurityContextHolder是Spring Security存储身份验证详细信息的地方。Spring Security并不关心Secur…

【C语言】深入理解函数指针

函数指针是 C 语言中一个非常有用且强大的概念&#xff0c;它允许我们将函数作为参数传递给其他函数、在运行时动态选择要调用的函数以及实现回调函数等功能。在本篇博客中&#xff0c;我们将深入探讨函数指针的概念、用法以及其在实际编程中的应用。 目录 前言 什么是函数指…

C++ 动态规划 状态压缩DP 蒙德里安的梦想

求把 NM 的棋盘分割成若干个 12 的长方形&#xff0c;有多少种方案。 例如当 N2&#xff0c;M4 时&#xff0c;共有 5 种方案。当 N2&#xff0c;M3 时&#xff0c;共有 3 种方案。 如下图所示&#xff1a; 2411_1.jpg 输入格式 输入包含多组测试用例。 每组测试用例占一行…

OCR文本纠错思路

文字错误类别&#xff1a;多字 少字 形近字 当前方案 文本纠错思路 简单&#xff1a; 一、构建自定义词典&#xff0c;提高分词正确率。不在词典中&#xff0c;也不是停用词&#xff0c;分成单字的数据极有可能是错字&#xff08;少部分可能是新词&#xff09;。错字与前后的…

webapi-元素的属性设置-图片切换的案例

元素的属性设置 1.目标 ​ 掌握图片的src属性的设置 在页面使用img标签显示一张图片, 点击这个图片更换一张新的图片 2.实现思路 使用img 指定src “路径” 指定id“one”获取img标签&#xff0c; 添加onclick 点击事件在事件处理程序函数体中修改图片的src的值 3.代码实…

uniapp设置不显示顶部返回按钮

一、pages文件中&#xff0c;在相应的页面中设置 "titleNView": {"autoBackButton": false} 二、对应的页面文件设置隐藏元素 document.querySelector(.uni-page-head-hd).style.display none

【Git】三棵“树”介绍

Git是一种分布式版本控制系统&#xff0c;它使用了三树原理来管理代码的变化和版本。 三树原理包括工作区树&#xff08;Working Tree&#xff09;、暂存区树&#xff08;Staging Area/Index&#xff09;和版本库树&#xff08;Commit/HEAD&#xff09;。 工作区树&#xff08…

计算机网络实验四

实验四 VLAN划分与配置 1、实验目的 • 理解并掌握Port Vlan的配置方法 • 理解并掌握掌握跨交换机实现VLAN的配置方法 2、实验设备 &#xff08;1&#xff09;实验内容1&#xff1a;交换机端口隔离—Port Vlan的配置 以太网交换机一台笔记本电脑一台PC机两台配置电缆、网…

二重指数和估计难多了

单变量指数和估计有指数对方法&#xff08;1933年英国人E.Phillips创造&#xff09;&#xff0c;印度人B.R.Srinivasan在1960年代搞出的二重指数对理论&#xff08;发表在 Math.Ann.)&#xff0c;由于没用二变量同步的Weyl不等式&#xff0c;是很肤浅的&#xff0c;而且1988年德…

收藏:相当大赞的来自 Agilean产品团队的2篇关于重塑敏捷组织的绩效管理的文章

Agilean产品团队&#xff0c;是吴穹博士领导下最近在国内敏捷界很厉害的产品&#xff0c;今天看到两篇相当不错的说敏捷组织的上下篇文章&#xff0c;分享下&#xff0c;地址是&#xff1a;6个原则15项举措&#xff0c;重塑敏捷组织的绩效管理&#xff08;上&#xff09; 6个原…

星宸科技SSC8826Q 驾驶辅助(ADAS)行车记录仪方案

星宸科技SSC8826Q 驾驶辅助&#xff08;ADAS&#xff09;行车记录仪方案 一、方案描述 SSC8826Q是高度集成的行车记录仪、流媒体后视镜解决方案&#xff0c;主芯片为ARM Cortex A53&#xff0c;dual core&#xff0c;主频高达1.2GHz&#xff0c;集成了64-bit dual-core RISC 处…

Windows 版Oracle 数据库(安装)详细过程

首先到官网上去下载oracle64位的安装程序 第一步&#xff1a;将两个datebase文件夹解压到同一目录中。 当下载完成后,它里面是两个文件夹 win64_11gR2_database_1of2, win64_11gR2_database_2of2,我们需要把其中的一个database文件夹整合在一起(复制一个database文件夹到另一…

如何有效的向 AI 提问 ?

目录 〇、导言 一、Base LLM 与 Instruction Tuned LLM 二、如何提出有效的问题 &#xff1f; 1. 明确问题&#xff1a; 2. 简明扼要&#xff1a; 3. 避免二义性&#xff1a; 4. 避免绝对化的问题&#xff1a; 5. 利用引导词&#xff1a; 6. 检查语法和拼写&#xff1…

哈希加密Python实现

一、代码 from cryptography.fernet import Fernet import os import bcrypt# 密钥管理和对称加密相关 def save_key_to_file(key: bytes, key_path: str):with open(key_path, wb) as file:file.write(key)def load_key_from_file(key_path: str) -> bytes:if not os.path…

【芯片设计- RTL 数字逻辑设计入门 7 -- 同步复位与异步复位详细介绍】

文章目录 复位的类型和划分同步复位综合后电路优缺点 异步复位优缺点 异步复位的时序分析&#xff08;recovery time/removal time&#xff09;异步复位&#xff0c;同步释放综合后电路优缺点 转自&#xff1a;https://blog.csdn.net/qq_40281783/article/details/128969188 复…

docker部署笔记系统flatnotes

效果 安装 创建目录 mkdir -p /opt/flatnotes/data && cd /opt/flatnotes/ chmod -R 777 /opt/flatnotes/ 创建并启动容器(可以自己修改账户和密码) docker run -d \ --restart unless-stopped \ --name flatnotes \ -p "10040:8080" \ -v "/dat…