动态规划——0-1背包问题

文章出处:极客时间《数据结构和算法之美》-作者:王争。该系列文章是本人的学习笔记。

1 0-1背包问题

背包能够承受的总重量一定w,每个物品的总量不同int[] weight表示。怎么放才能让背包中物品的总重量最大。

每次决定一种物品,要不要放入到背包中。当物品放完了或者总重量等于w,就停止放入,选择最大的总量保存下来。

2 用回溯法实现

 public class Package {private int[] weight =  new int[]{2,2,4,6,3};private int n = 5;//物品个数private int w = 9;//背包承受的最大重量private int maxW = Integer.MIN_VALUE;//结果/*** 处理第i个物品的情况,当前重量是cw* 这是回溯法,复杂度是指数级的。有些状态会计算多次。* @param i* @param cw*/public void f(int i,int cw){if(cw==w || i==n){maxW =Math.max(cw,maxW);return;}f(i+1,cw);//第i个物品,不装入背包if(cw+weight[i]<=w){f(i+1,cw+weight[i]);//第i个物品,装入背包}}public int maxWeight(){f(0,0)return maxW;}
}

我们根据上面这个特殊的例子,把回溯求解问题的递归树画出来。
在这里插入图片描述
递归树中的每个节点表示一个状态,用(i,cw)表示。i 表示要将要处理第i个物品,cw表示当前总重量。例如(2,2)表示我们将要处理第2个物品,在处理之前已经放入的物品总重量是2。
从递归树中能看到某些状态被重复计算了,例如f(2, 2) 和 f(3,4)被计算了两次。为了解决这个问题,可以有两种方法解决。

3 第一种:备忘录

我们可以使用备忘录,遇到状态已经计算过的就不再计算了。改进代码如下。

private boolean[][] mem = new boolean[n][w+1];/*** 记录状态,已经计算过的状态就不再计算了* @param i* @param cw*/public void fV2(int i,int cw){if(cw==w || i==n){maxW =Math.max(cw,maxW);return;}if(mem[i][cw]) return;mem[i][cw] = true;f(i+1,cw);//第i个物品,不装入背包if(cw+weight[i]<=w){f(i+1,cw+weight[i]);//第i个物品,装入背包}}

4 第二种:动态规划

我们把整个过程看做n个阶段,每个阶段只决策一种物品是否放入。每个物品决策(放或者不放)完成之后,背包中物品的重量会有多种情况。也就是说会有多种状态,对应递归树中不同的节点。

我们把每一层重复的节点合并,只记录不同的状态。基于上一层的状态集合,推导下一层集合的状态。我们合并每一层的状态,保证每一层节点个数不会超过w个。这样就避免了每一层状态节点个数指数级增长。

我们用states[n][w+1]来记录每一层可以达到的不同状态。例如上面例子中分析有(2,2)这个节点,那么states[2][2]=true。

第0个物品的重量是2,要么装入背包,要么不装入背包,决策之后会对应背包中的两种状态,背包中的总总量是0或者2.我们用state[0][0]=true,state[0][2]=true来表示这两种状态。

第1个物品的重量是2,要么装入背包,要么不装入背包,决策之后对应的背包状态:
  0+0=0
  0+2=2
  2+2=4
  这是基于上一步背包的状态计算得到的
  我们用state[1][0]=true state[1][2]=true state[1][4]=true 来表示。
  
以此类推,一直到第n-1个物品。找到state[n-1] 的 数组中找到最大的state[n-1][j]=true,返回j。

4.1 状态表

这个过程用状态表来表示,就是下图。

在这里插入图片描述在这里插入图片描述
代码如下。代码时间复杂度O(n*w)。

public int knapsnack(int[] weight,int n,int w){boolean[][] states = new boolean[n][w+1];states[0][0] = true;if(weight[0]<w){states[0][weight[0]] = true;}for(int i=1;i<n;i++){for(int j=0;j<w;j++){if(states[i-1][j]==true){states[i][j] = true;}}for(int j=0;j<=w-weight[i];j++){if(states[i-1][j]==true){states[i][j+weight[i]] = true;}}}for(int j=w;j>=0;j--){if(states[n-1][j]) return j;}return 0;}

上面的代码实现用到二维数组。经过观察,我们发现,每次for循环里面,在计算states[i]的时候,只与states[i-1]有关系。我们应该只用一维数组就能实现。

	public int knapsnackV2(int[] weight,int n,int w){boolean[] states = new boolean[w+1];states[0] = true;if(weight[0]<w){states[weight[0]] = true;}for(int i=1;i<n;i++){//使用一维数组需要从后向前计算,否则会有多余的计算for(int j=w-weight[i];j>=0;j--){if(states[j]==true){states[j+weight[i]] = true;}}}for(int j=w;j>=0;j--){if(states[j]) return j;}return 0;}

4.2 状态方程

这道题目用状态方程来表示不太好表示。
2021-10-25:再次看这个状态方程是可以表示的。
state[i][j]=true表示当第i个物品决策完之后,背包可能的重量是j。
state[i][j]=false表示当第i个物品决策完之后,背包不可能是j。

state[i][j]=true, if state[i-1][j]=true
state[i][j+weights[i]] = true, if state[i-1][j]=true and j+weights[i]<=w(不超重)

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

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

相关文章

第五十四期:MongoDB与MySQL:如何选择

MongoDB和MySQL分别是领先的开源NoSQL和关系数据库。哪个最适合您的应用程序? 作者&#xff1a;XEyes行走的CODE来源 MongoDB和MySQL分别是领先的开源NoSQL和关系数据库。哪个最适合您的应用程序? 在1990年代的互联网泡沫时期&#xff0c;用于Web应用程序的一种通用软件堆栈…

动态规划——矩阵中的最短路径长度

文章出处&#xff1a;极客时间《数据结构和算法之美》-作者&#xff1a;王争。该系列文章是本人的学习笔记。 题目 假设我们有一个 n 乘以 n 的矩阵 w[n][n]。矩阵存储的都是正整数。棋子起始位置在左上角&#xff0c;终止位置在右下角。我们将棋子从左上角移动到右下角。每次…

[密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第19篇]Shamir密钥交换场景

这是一系列博客文章中最新的一篇&#xff0c;该文章列举了“每个博士生在做密码学时应该知道的52件事”:一系列问题的汇编是为了让博士生们在第一年结束时知道些什么。 Shamir密钥交换场景是一个被Adi Shamir提出的算法.算法允许多方分割一个密码,例如一个密钥.当足够多的秘密结…

第五十五期:MongoDB数据库误删后的恢复

如果部署的是 MongoDB 复制集&#xff0c;这时还有一线希望&#xff0c;可以通过 oplog 来尽可能的恢复数据;MongoDB 复制集的每一条修改操作都会记录一条 oplog&#xff1b;如果对 MongoDB 做了全量备份 增量备份&#xff0c;那么可以通过备份集及来恢复数据。 作者&#xf…

037-PHP如何返回闭包函数实例

<?php /*: 如何返回闭包函数实例*/# 直接调用将不会输出$txt的内容function demo(){$txt 我爱PHP;$func function () use ($txt) {echo $txt;};# 这里不再直接调用&#xff0c;而且是把实例返回return $func; # 区别于直接写 $func;}# 测试一下 $res demo(); // 函数返…

动态规划——莱文斯坦距离

文章出处&#xff1a;极客时间《数据结构和算法之美》-作者&#xff1a;王争。该系列文章是本人的学习笔记。 莱文斯坦距离 在搜索引擎中会有搜索词纠错的功能。这个功能背后的原理是编辑距离。 编辑距离 编辑距离是量化两个词之间的相似度。 编辑距离是指将一个字符串变为…

[密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第18篇]画一个/描述ECB,CBC,CTR模式的操作

操作模式:块密码的安全性依赖于加解密一个固定长度的明文块.当加密或者解密消息的时候,块是被需要的.我们使用一种操作模式将明文的多个块链接在一起.我们会知道,这种链接在一起的方法是十分重要. 电子密码本(ECB)模式:加密,解密. ECB模式是最直接的方法.明文被分割成m块.每一…

[密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第20篇]Merkle-Damgaard hash函数如何构造

这里讲的是MD变换,MD变换的全称为Merkle-Damgaard变换.我们平时接触的hash函数都是先构造出一个防碰撞的压缩函数.然后先证明这个小的,固定长度的压缩函数是安全的,然后再用它构造一个任意长度的哈希算法.虽然存在很多其它的构造方法,MD是迄今为止最常用的(至少是被用到最多的)…

第五十六期:IPv6只是增加了地址数量?其实真相并没有那么简单!

究竟什么是IPv6?它到底是干啥用的?IPv6的全称是Internet Protocol version 6。其中&#xff0c;Internet Protocol译为“互联网协议”。所以&#xff0c;IPv6就是互联网协议第6版。 作者&#xff1a;小枣君 10月20日&#xff0c;在乌镇举办的第六届世界互联网大会上&#x…

spring学习(10):创建项目(自动装配)

首先创建项目 pom.xml的配置文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://mav…

[密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第21篇]CRT算法如何提高RSA的性能?

CRT加速RSA&#xff1a;https://www.di-mgt.com.au/crt_rsa.html 转载链接&#xff1a;https://www.cnblogs.com/zhuowangy2k/p/12245513.html

动态规划——最长递增子序列

题目 我们有一个数字序列包含 n 个不同的数字&#xff0c;如何求出这个序列中的最长递增子序列长度&#xff1f;比如 2, 9, 3, 6, 5, 1, 7 这样一组数字序列&#xff0c;它的最长递增子序列就是 2, 3, 5, 7&#xff0c;所以最长递增子序列的长度是 4。 回溯法 数组长度为n&a…

spring学习(11):使用配置类

CompactDisc类 package soundSystem;import org.springframework.stereotype.Component;Component public class CompactDisc {public CompactDisc() {super();System.out.println("compactdisc无参构造方法");}public void play(){System.out.println("正在播…

[密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第22篇]如何用蒙哥马利算法表示一个数字和多个相乘的数字

这是一系列博客文章中最新的一篇&#xff0c;该文章列举了“每个博士生在做密码学时应该知道的52件事”:一系列问题的汇编是为了让博士生们在第一年结束时知道些什么。 安全和效率 密码学的目标是设计高度安全的密码学协议,但是同时这些协议也应该被有效率的实现.这样就可以一…

动态规划——双11既可以薅羊毛还能花钱最少

淘宝的“双十一”购物节有各种促销活动&#xff0c;比如“满 200 元减 50 元”。假设你的购物车中有 n 个&#xff08;n>100&#xff09;想买的商品&#xff0c;希望从里面选几个&#xff0c;在凑够满减条件的前提下&#xff0c;让选出来的商品价格总和最大程度地接近满减条…

spring学习(12):使用junit4进行单元测试

pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 …

[密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第23篇]写一个实现蒙哥马利算法的C程序

这是一系列博客文章中最新的一篇&#xff0c;该文章列举了“每个博士生在做密码学时应该知道的52件事”:一系列问题的汇编是为了让博士生们在第一年结束时知道些什么。 这次博客我将通过对蒙哥马利算法的一个实际的实现&#xff0c;来补充我们上周蒙哥马利算法的理论方面。这个…

spring学习(13):使用junit4进行单元测试续

加入spring test.jar包 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven…

《java程序员修炼之道》pdf书籍

链接&#xff1a;https://pan.baidu.com/s/1bbsTPCpUNI9klh40-8Be7w 提取码&#xff1a;pc57 转载于:https://www.cnblogs.com/pyweb/p/10995145.html

[密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第24篇]描述一个二进制m组的滑动窗口指数算法

这是一系列博客文章中最新的一篇&#xff0c;该文章列举了“每个博士生在做密码学时应该知道的52件事”:一系列问题的汇编是为了让博士生们在第一年结束时知道些什么。 二进制算法 二进制模幂算法和传统的求幂的二次方方法非常像。实际上&#xff0c;唯一的不同就是我们把N表示…