news 2026/3/8 7:34:10

0x3f第12天 0-1背包

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
0x3f第12天 0-1背包

1.0-1背包问题:

#capacity :背包容量

#w[i]:第i个物体的体积

#v[i]:第i个物体的价值

def dfs(i , c): 定义:选或不选到第i个物体时,目前背包最大价值

i:目前装了i个物体 c:背包剩余容量

回溯公式:

dfs(i,c)=max(dfs(i-1,c),dfs(i-1,c-w[i])+v[i]) 装没装第i个物体的两种情况

边界条件:1.i == 0 没东西可装

2. 剩余容量不足以装下当前的这个w[ i ]

#capacity :背包容量 #w[i]:第i个物体的体积 #v[i]:第i个物体的价值 n = len(w) def dfs(i,c): if i < 0: return 0 if c < w[i]: return dfs(i-1,c) return max(dfs(i-1,c),dfs(i-1,c-w[i])+v[i]) dfs(n-1,capacity)



1.1.目标和 问题

1.回溯法+cache

目标和问题可以转换为0-1背包问题,因为最后也是从数组中选出几个数,使其最终和为一个定值

令p:正数和,q:负数和 sums = p-q target = p+q

可以得出 p = (sum+target)//2 即几个数和为定值

dfs(i,t)定义:从i个数中选出和为t的 方案个数

参数i:从包括i及其往前的数字中选

t:现在要凑的目标和

回溯方程:

dfs(i,t) = dfs(i-1,t) + dfs(i-1,t-nums[i])

边界条件:若sum+target并不是偶数,或者为负数,那就无解,返回 0

边界条件:若当前的nums[i] > t,那就加不进去,return dfs(i-1,t)

初始条件:if i < 0: //没有可选的了,从n已经遍历到开头了

if t==0:return 1 此方案可行

else: return 0 没有恰好为t的方案

代码:

时间复杂度:t*n空间复杂度::n

时间复杂度你可以把这个dfs函数的执行过程,理解成 “填一张 n 行、t 列的表格”:

class Solution: def findTargetSumWays(self, nums: List[int], target: int) -> int: target = sum(nums)+target n = len(nums) if target%2 != 0 or target<0: return 0 t = target//2 @cache def dfs(i,t): if i<0: if t==0: return 1 else: return 0 if nums[i]>t: return dfs(i-1,t) return dfs(i-1,t) + dfs(i-1,t-nums[i]) return dfs(n-1,t)

2.递推

先根据回溯公式写出f公式:

dfs(i,t) = dfs(i-1,t) + dfs(i-1,t-nums[i])

f[i][t] = f[i-1][t] + f[i-1][t-nums[i]]数组最好不要出现负数情况

f [ i + 1 ] [ t ] = f [ i ] [ t ] + f [ i ] [ t - nums[ i ] ]

于是自然想到建立一个f[[]]二维数组 为了边界条件,我们的二维数组会多一列、一行

公式:f = [ [0] *(t +1) for _ in range(n+1) ] *的是列数量 for的是行数量

n+1对于前0个,1个...n个元素

t 对应 凑出和为0 ,1 ,...t的数

递归变循环,怎么变,取决于f公式需要什么

f [ i + 1 ] [ t ] = f [ i ] [ t ] + f [ i ] [ t - nums[ i ] ] 可以看出需要 i , t , nums[ i ]

for i,x in enumerate(nums):

for c in range(t+1):

边界条件:nums[i]>t: 在这就是 x>c

时间复杂度:t n 空间复杂度 t n

class Solution: def findTargetSumWays(self, nums: List[int], target: int) -> int: target = sum(nums)+target n = len(nums) if target%2 != 0 or target<0: return 0 t = target//2 f = [[0]*(t+1)for _ in range(n+1)] f[0][0]=1 for i,x in enumerate(nums): for c in range(t+1): if x>c: f[i+1][c] = f[i][c] else: f[i+1][c] = f[i][c]+f[i][c-x] return f[n][t]

3.空间优化两个数组

发现f[i+1]只取决于f[i],所以只需要两个数字

之后的数组重新覆盖f0和f1即可

f = [[0]*(t+1)for _ in range(2)] 两行数组

f[i+1]都改成f[(i+1)%2]

f[i]都改成f[i%2]

空间复杂度为 t

4.空间优化一个数组

和i有关的都删掉,遍历target的时候倒着遍历,从t遍历至x,倒序到 x,只处理 c≥x 的场景,避免重复选,最开始的边界条件

时间复杂度 tn 空间复杂度t

class Solution: def findTargetSumWays(self, nums: List[int], target: int) -> int: target = sum(nums)+target n = len(nums) if target%2 != 0 or target<0: return 0 t = target//2 f =[0]*(t+1) f[0]=1 for x in nums: for c in range(t,x-1,-1): f[c] = f[c]+f[c-x] return f[t]



2.完全背包

每个物品可以重复选,回溯公式修改:

dfs(i,c)=max(dfs(i-1,c),dfs(i-1, c-w[i])+v[i])

dfs (i,c) = min(dfs(i-1,c),dfs(i, c-w[i])+v[i])选了,但还可以选,所以i不变

2.1 零钱兑换

1.回溯法+cache

dfs(i,c)定义:用前i种硬币,凑c块钱,最少用几个硬币

i:前i种硬币

c:还需要凑c块钱

回溯方程:

dfs(i,c) = min(dfs(i-1,c) + dfs(i-,c-coins[i])+1)

边界条件:

1.若 coins[i]>c,return dfs(i-1,c) 这类硬币滚蛋

2.若i < 0 andc!=0,说明还没凑完,return inf 无解

起始条件:

若 i<0 and c==0,return 0所有硬币都处理完了,且剩余要凑的金额是 0不需要再用任何硬币

i < 0c == 0→ 返回 0
  • 含义:所有硬币都处理完了,且剩余要凑的金额是 0(已经凑够了);
  • 为什么返回 0?因为 “没有硬币可选” 的情况下,凑够了金额 0,不需要再用任何硬币→ 最少硬币数就是 0;
  • 举例子:比如你要凑金额 0,不管有没有硬币,都只需要 0 个硬币(啥都不用选),这是所有最值问题的 “基础锚点”。
  • class Solution: def coinChange(self, coins: List[int], amount: int) -> int: n = len(coins) @cache def dfs(i,c): if i<0: if c==0:return 0 else: return inf if coins[i] > c: return dfs(i-1,c) return min(dfs(i-1,c),dfs(i,c-coins[i])+1) ans = dfs(n-1,amount) if ans < inf: return ans else: return -1
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/28 17:13:19

USB转串口驱动安装新手教程:从下载到配置全流程

从零搞定USB转串口通信&#xff1a;CH340与CP2102驱动安装全解析 你有没有遇到过这样的场景&#xff1f;手里的开发板插上电脑后&#xff0c;设备管理器里只显示“未知设备”&#xff0c;串口助手打不开COM口&#xff0c;调试信息出不来——明明线都接对了&#xff0c;却卡在第…

作者头像 李华
网站建设 2026/3/7 15:44:38

基于Python+大数据+SSM新能源汽车数据分析系统(源码+LW+调试文档+讲解等)/新能源车数据平台/电动汽车数据分析/新能源车辆数据系统/新能源汽车数据研究/新能源车辆信息分析系统

博主介绍 &#x1f497;博主介绍&#xff1a;✌全栈领域优质创作者&#xff0c;专注于Java、小程序、Python技术领域和计算机毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅&#x1f447;&#x1f3fb; 2025-2026年最新1000个热门Java毕业设计选题…

作者头像 李华
网站建设 2026/2/28 3:19:22

LangFlow养生食谱个性化推荐引擎

LangFlow养生食谱个性化推荐引擎 在健康管理日益智能化的今天&#xff0c;用户不再满足于千篇一律的饮食建议。他们希望获得真正“懂自己”的营养指导——比如根据体质、节气甚至情绪状态&#xff0c;推荐一道温补又不燥热的汤品。然而&#xff0c;构建这样一套融合中医理论与大…

作者头像 李华
网站建设 2026/2/27 20:14:51

ESP32 IDF Wi-Fi连接+HTTP请求完整示例

从零开始&#xff1a;用 ESP-IDF 实现 ESP32 的 Wi-Fi 联网与 HTTP 数据交互 你有没有遇到过这样的场景&#xff1f;手头有一块 ESP32&#xff0c;想让它把传感器数据上传到云端 API&#xff0c;却发现连最基本的“连上 Wi-Fi 发个 HTTP 请求”都卡住了——不是连不上网络&…

作者头像 李华
网站建设 2026/3/4 21:32:17

【API 设计之道】08 流量与配额:构建基于 Redis 的分布式限流器

大家好&#xff0c;我是Tony Bai。欢迎来到我们的专栏 《API 设计之道&#xff1a;从设计模式到 Gin 工程化实现》的第八讲。在上一讲中&#xff0c;我们给 API 穿上了“防弹衣”&#xff0c;通过幂等性设计防止了重复请求的数据污染。今天&#xff0c;我们要给 API 装上“红绿…

作者头像 李华
网站建设 2026/3/4 3:17:45

LangFlow灯谜创作助手实现过程

LangFlow灯谜创作助手实现过程 在人工智能加速渗透创意领域的今天&#xff0c;一个有趣的问题浮现出来&#xff1a;我们能否让大模型不仅“会答题”&#xff0c;还能“出题”&#xff1f;比如&#xff0c;让它像古人一样&#xff0c;为“中秋赏月”拟一则意境悠远的灯谜&#x…

作者头像 李华