动态规划算法--01背包问题详细讲解步骤

news2024/11/24 13:29:27

举个例子

要确定哪些物品被放入背包以达到最大价值,可以在计算 dp 数组的同时记录选择的物品。具体来说,可以使用一个额外的数组来记录每个状态的选择情况。以下是一个详细的步骤和代码实现:
在这里插入图片描述
在这里插入图片描述

n = 3
W = 5
weights = [2, 1, 3]
values = [6, 3, 5]

初始化 dp 和 choice 数组

dp = [[0] * (W + 1) for _ in range(n + 1)]
choice = [[0] * (W + 1) for _ in range(n + 1)]

print("初始状态:")
print("dp:")
for row in dp:
    print(row)
print("choice:")
for row in choice:
    print(row)

初始状态:
在这里插入图片描述

第1个物品(重量2,价值6)

# 第1个物品
for j in range(1, W + 1):
    if j >= weights[0]:
        if dp[0][j] < dp[0][j - weights[0]] + values[0]:
            dp[1][j] = dp[0][j - weights[0]] + values[0]
            choice[1][j] = 1
        else:
            dp[1][j] = dp[0][j]
    else:
        dp[1][j] = dp[0][j]

print("处理第1个物品后:")
print("dp:")
for row in dp:
    print(row)
print("choice:")
for row in choice:
    print(row)

在这里插入图片描述

第2个物品(重量1,价值3)

# 第2个物品
for j in range(1, W + 1):
    if j >= weights[1]:
        if dp[1][j] < dp[1][j - weights[1]] + values[1]:
            dp[2][j] = dp[1][j - weights[1]] + values[1]
            choice[2][j] = 1
        else:
            dp[2][j] = dp[1][j]
    else:
        dp[2][j] = dp[1][j]

print("处理第2个物品后:")
print("dp:")
for row in dp:
    print(row)
print("choice:")
for row in choice:
    print(row)

在这里插入图片描述

第3个物品(重量3,价值5)

for j in range(1, W + 1):
    if j >= weights[2]:
        if dp[2][j] < dp[2][j - weights[2]] + values[2]:
            dp[3][j] = dp[2][j - weights[2]] + values[2]
            choice[3][j] = 1
        else:
            dp[3][j] = dp[2][j]
    else:
        dp[3][j] = dp[2][j]

print("处理第3个物品后:")
print("dp:")
for row in dp:
    print(row)
print("choice:")
for row in choice:
    print(row)

在这里插入图片描述

回溯路径

在这里插入图片描述
在这里插入图片描述

# 回溯路径,确定选择的物品
selected_items = []
j = W
for i in range(n, 0, -1):
    if choice[i][j] == 1:
        selected_items.append(i - 1)  # 物品编号从0开始
        j -= weights[i-1]

# 返回最大价值和选择的物品
max_value = dp[n][W]
selected_items = selected_items[::-1]

print(f"最大价值: {max_value}")
print(f"选择的物品: {selected_items}")

在这里插入图片描述
最终,选择的物品是第2个(编号1)和第3个(编号2)物品,最大价值为11。

完整代码

def knapsack_with_items(n, W, weights, values):
    # 初始化 dp 和 choice 数组
    dp = [[0] * (W + 1) for _ in range(n + 1)]
    choice = [[0] * (W + 1) for _ in range(n + 1)]
    
    # 填充 dp 和 choice 数组
    for i in range(1, n + 1):
        for j in range(1, W + 1):
            if j >= weights[i-1]:
                if dp[i-1][j] < dp[i-1][j-weights[i-1]] + values[i-1]:
                    dp[i][j] = dp[i-1][j-weights[i-1]] + values[i-1]
                    choice[i][j] = 1
                else:
                    dp[i][j] = dp[i-1][j]
            else:
                dp[i][j] = dp[i-1][j]
    
    # 回溯路径,确定选择的物品
    selected_items = []
    j = W
    for i in range(n, 0, -1):
        if choice[i][j] == 1:
            selected_items.append(i - 1)  # 物品编号从0开始
            j -= weights[i-1]
    
    # 返回最大价值和选择的物品
    return dp[n][W], selected_items[::-1]

# 示例
n = 3
W = 5
weights = [2, 1, 3]
values = [6, 3, 5]
max_value, selected_items = knapsack_with_items(n, W, weights, values)
print(f"最大价值: {max_value}")
print(f"选择的物品: {selected_items}")

一维数组的栗子

使用一维数组可以优化空间复杂度,将空间复杂度从O(nW) 降低到 O(W)。我们可以通过滚动数组的方式来实现这一点。
在这里插入图片描述

注意:从后往前遍历背包容量

如果背包容量j从前往后会出现什么问题呢?

n = 3
W = 5
weights = [2, 1, 3]
values = [6, 3, 5]

# 初始化 dp 数组
dp = [0] * (W + 1)

print("初始状态:")
print("dp:", dp)

# 第1个物品
for j in range(weights[0], W + 1):
    if dp[j] < dp[j - weights[0]] + values[0]:
        dp[j] = dp[j - weights[0]] + values[0]

print("处理第1个物品后:")
print("dp:", dp)

在这里插入图片描述
从前往后遍历背包容量 j 会导致同一个物品被多次选择,从而违反了01背包问题的约束。例如,在处理第1个物品时,当 j=4 时,dp[4] 被更新为 dp[2] + 6,而 dp[2] 已经被更新过,导致物品1被重复使用。

初始化

在这里插入图片描述

第1个物品(重量2,价值6)

for j in range(W, weights[0] - 1, -1):
    if dp[j] < dp[j - weights[0]] + values[0]:
        dp[j] = dp[j - weights[0]] + values[0]
        choice[1][j] = 1

print("处理第1个物品后:")
print("dp:", dp)
print("choice:")
for row in choice:
    print(row)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

第2个物品(重量1,价值3)

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

第3个物品(重量3,价值5)

在这里插入图片描述

回溯路径

在这里插入图片描述

完整代码

def knapsack_with_items_one_dim(n, W, weights, values):
    # 初始化 dp 数组
    dp = [0] * (W + 1)
    # 初始化 choice 数组,用于记录选择的物品
    choice = [[0] * (W + 1) for _ in range(n + 1)]
    
    # 填充 dp 和 choice 数组
    for i in range(1, n + 1):
        for j in range(W, weights[i-1] - 1, -1):
            if dp[j] < dp[j - weights[i-1]] + values[i-1]:
                dp[j] = dp[j - weights[i-1]] + values[i-1]
                choice[i][j] = 1
    
    # 回溯路径,确定选择的物品
    selected_items = []
    j = W
    for i in range(n, 0, -1):
        if choice[i][j] == 1:
            selected_items.append(i - 1)  # 物品编号从0开始
            j -= weights[i-1]
    
    # 返回最大价值和选择的物品
    return dp[W], selected_items[::-1]

# 示例
n = 3
W = 5
weights = [2, 1, 3]
values = [6, 3, 5]
max_value, selected_items = knapsack_with_items_one_dim(n, W, weights, values)
print(f"最大价值: {max_value}")
print(f"选择的物品: {selected_items}")

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

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

相关文章

Jenkins的环境部署

day22 回顾 Jenkins 简介 官网Jenkins Jenkins Build great things at any scale The leading open source automation server, Jenkins provides hundreds of plugins to support building, deploying and automating any project. 用来构建一切 其实就是用Java写的一个项目…

微软发布Win11 24H2系统11月可选更新KB5046740!

系统之家11月22日报道&#xff0c;微软针对Win11 24H2系统推出2024年11月最新可选更新补丁KB5046740&#xff0c;更新后系统版本后升至26100.2454&#xff0c;此次更新后修复当应用程序以PDF和XLSX格式导出图表对象时停止响应、无法使用API查找旋转信息等问题。以下小编将给大家…

JavaEE 实现 登录+注册(采用注解方式链接数据库)

&#xff08;Spring MVC的Controller练习&#xff09; 工具&#xff1a;Tomcat 10.0.23&#xff0c;MySQL&#xff0c;JDK18 一、运行效果展示 点击运行Tomcat首先进入index.jsp页面 若已有账号点击登录即可进行登录&#xff0c;这里先点击“获取ROY6账号”去注册&#xff0…

用 React18 构建点击计分小游戏

本教程将带你创建一个简单的点击计分游戏&#xff0c;使用 React 和基本的 Hooks。游戏规则很简单&#xff1a;在 10 秒内尽可能多地点击按钮以获取高分。 项目结构 确保你的项目结构如下&#xff1a; 编写 ClickGame 组件 在 src/ClickGame.js 文件中&#xff0c;编写如下…

Halo 正式开源: 使用可穿戴设备进行开源健康追踪

在飞速发展的可穿戴技术领域&#xff0c;我们正处于一个十字路口——市场上充斥着各式时尚、功能丰富的设备&#xff0c;声称能够彻底改变我们对健康和健身的方式。 然而&#xff0c;在这些光鲜的外观和营销宣传背后&#xff0c;隐藏着一个令人担忧的现实&#xff1a;大多数这些…

数据结构:链表进阶

链表进阶 1. ArrayList的缺陷2. 链表2.1 链表的概念及结构2.2 链表的实现 3.链表面试题4.LinkedList的使用5.1 什么是LinkedList4.2 LinkedList的使用 5. ArrayList和LinkedList的区别 1. ArrayList的缺陷 通过源码知道&#xff0c;ArrayList底层使用数组来存储元素&#xff1…

第二十二周机器学习笔记:动手深度学习之——线性代数

第二十周周报 摘要Abstract一、动手深度学习1. 线性代数1.1 标量1.2 向量1.3 矩阵1.4 张量1.4.1 张量算法的基本性质 1.5 降维1.5.1 非降维求和 1.6 点积1.6.1 矩阵-向量积1.6.2 矩阵-矩阵乘法 1.7 范数 总结 摘要 本文深入探讨了深度学习中的数学基础&#xff0c;特别是线性代…

Flink-Source的使用

Data Sources 是什么呢&#xff1f;就字面意思其实就可以知道&#xff1a;数据来源。 Flink 做为一款流式计算框架&#xff0c;它可用来做批处理&#xff0c;也可以用来做流处理&#xff0c;这个 Data Sources 就是数据的来源地。 flink在批/流处理中常见的source主要有两大类…

分公司如何纳税

分公司不进行纳税由总公司汇总纳税“子公司具有法人资格&#xff0c;依法独立承担民事责任;分公司不具有法人资格&#xff0c;其民事责任由公司承担。”企业设立分支机构&#xff0c;使其不具有法人资格&#xff0c;且不实行独立核算&#xff0c;则可由总公司汇总缴纳企业所得税…

亚马逊搜索关键词怎么写?

在亚马逊这个全球领先的电子商务平台&#xff0c;如何让自己的产品被更多的消费者发现&#xff0c;是每一个卖家都需要深入思考的问题。而搜索关键词&#xff0c;作为连接卖家与买家的桥梁&#xff0c;其重要性不言而喻。那么&#xff0c;如何撰写有效的亚马逊搜索关键词呢&…

跨视角差异-依赖网络用于体积医学图像分割|文献速递-生成式模型与transformer在医学影像中的应用

Title 题目 Cross-view discrepancy-dependency network for volumetric medical imagesegmentation 跨视角差异-依赖网络用于体积医学图像分割 01 文献速递介绍 医学图像分割旨在从原始图像中分离出受试者的解剖结构&#xff08;例如器官和肿瘤&#xff09;&#xff0c;并…

基本功能实现

目录 1、环境搭建 2、按键控制灯&电机 LED 电机 垂直按键(机械按键) 3、串口调试功能 4、定时器延时和定时器中断 5、振动强弱调节 6、万年历 7、五方向按键 1、原理及分析 2、程序设计 1、环境搭建 需求: 搭建一个STM32F411CEU6工程 分析: C / C 宏定义栏…

C++11新特性探索:Lambda表达式与函数包装器的实用指南

文章目录 前言&#x1f349;一、Lambda表达式&#xff08;匿名函数&#xff09;&#x1f353;1.1 Lambda 表达式的基本语法&#x1f353;1.2 示例&#xff1a;基本 Lambda 表达式&#x1f353;1.3 捕获列表&#xff08;Capture&#xff09;&#x1f353;1.4 使用 Lambda 表达式…

msvcp110.dll丢失修复的多种科学方法分析,详细解析msvcp110.dll文件

遇到“msvcp110.dll丢失”的错误时&#xff0c;这表明你的系统缺少一个关键文件&#xff0c;但解决这一问题比较直接。本文将指导你通过几个简单的步骤迅速修复此错误&#xff0c;确保你的程序或游戏可以顺利运行。接下来的操作将非常简洁明了&#xff0c;易于理解和执行。 一.…

HDR视频技术之四:HDR 主要标准

HDR 是 UHD 技术中最重要维度之一&#xff0c;带来新的视觉呈现体验。 HDR 技术涉及到采集、加工、传输、呈现等视频流程上的多个环节&#xff0c;需要定义出互联互通的产业标准&#xff0c;以支持规模化应用和部署。本文整理当前 HDR 应用中的一些代表性的国际标准。 1 HDR 发…

Bug Fix 20241122:缺少lib文件错误

今天有朋友提醒才突然发现 gitee 上传的代码存在两个很严重&#xff0c;同时也很低级的错误。 因为gitee的默认设置不允许二进制文件的提交&#xff0c; 所以PH47框架下的库文件&#xff08;各逻辑层的库文件&#xff09;&#xff0c;以及Stm32Cube驱动的库文件都没上传到Gi…

c++源码阅读__smart_ptr__正文阅读

文章目录 简介源码解析1. 引用计数的实现方式2. deleter静态方法的赋值时间节点3.make_smart的实现方式 与 好处4. 几种构造函数4.1 空构造函数4.2 接收指针的构造函数4.3 接收指针和删除方法的构造函数 , 以及auto进行模板lambda的编写4.4 拷贝构造函数4.5 赋值运算符 5. rele…

【BUG】ES使用过程中问题解决汇总

安装elasticsearch内存不足问题 问题回顾 运行kibana服务的时候&#xff0c;无法本地访问 解决 首先排查端口问题&#xff0c;然后检查错误日志 无法运行kibana服务&#xff0c;是因为elasticsearch没有启动的原因 发现致命错误&#xff0c;确定是elasticsearch服务没有运行导…

C语言--分支循环编程题目

第一道题目&#xff1a; #include <stdio.h>int main() {//分析&#xff1a;//1.连续读取int a 0;int b 0;int c 0;while (scanf("%d %d %d\n", &a, &b, &c) ! EOF){//2.对三角形的判断//a b c 等边三角形 其中两个相等 等腰三角形 其余情…

Linux——用户级缓存区及模拟实现fopen、fweite、fclose

linux基础io重定向-CSDN博客 文章目录 目录 文章目录 什么是缓冲区 为什么要有缓冲区 二、编写自己的fopen、fwrite、fclose 1.引入函数 2、引入FILE 3.模拟封装 1、fopen 2、fwrite 3、fclose 4、fflush 总结 前言 用快递站讲述缓冲区 收件区&#xff08;类比输…