[TOC]
# 完全背包
## 问题及背景
今天是蛋糕店开张第三天啦💕,也是活动的最后一天了,老板决定加大活动力度,**每种蛋糕不限量**!!,也就是说在上一节的01背包中我们每一种蛋糕最多只能拿一个,但是今天你可以任意拿(只要你的背包能放的下)。
## 分析
首先可以知道,虽然说蛋糕不限量,但是背包的大小是一定的,对于每一种蛋糕可以算出一个最大能装下的数量`max[i]`,然后从0到`max[i]`枚举数量就可以了。
这样做的时间复杂度是O(n\*v\^2),这是不能接受的。
更换思路,在上一节01背包中我们提到过,枚举背包容量`j`时,我们要从大到小枚举,那么我们如果从小到大枚举会发生什么呢?
没错,恰恰就是完全背包的枚举方式。
可以归纳性证明:
当枚举到`cost[i]`时,方程会更新拿一个`i`个物品,判断最大价值会不会更大。在枚举到`2*cost[i]`时,方程会更新再拿一个`i`物品,判断最大价值会不会更大,因为之前更新了拿一个`i`物品的状态,所以此次拿是第2个,以此类推。。。
### 复杂度和代码
时间复杂度:O(n*v)
空间复杂度:O(v)
代码如下:
~~~py
n, v = map(int, input().split())
cost = [0 for i in range(n)]
val = [0 for i in range(n)]
for i in range(n):
c, vl = map(int, input().split())
cost[i], val[i] = c, vl
dp = [0 for i in range(v+1)]
for i in range(n):
for j in range(cost[i], v + 1):
'''
首先,j>=cost[i],不然这个背包装不下这个物品。
另外,需要注意我们枚举j是从小到大的,这点尤其重要。
这个顺序可以保证我们每一个物品可取任意次。
'''
dp[j] = max(dp[j], dp[j-cost[i]]+val[i])
print(dp[v])
~~~
- 简介
- 零基础快速入门ACM
- C语言快速入门
- C语言快速入门
- C/C++基础
- 输入输出
- 数组和字符串
- 数组
- 字符数组
- 函数和递归
- C++标准容器库(STL)
- Vector
- Map
- Set
- String
- Stack
- Queue
- Priority_queue
- 贪心
- 硬币问题
- 区间调度问题
- 字典序最小问题
- 独木舟问题
- 搜索
- DFS
- BFS
- 剪枝
- 记忆化搜索
- 常用技巧
- 倍增
- 高精度
- 大数加法
- 大数减法
- 大数乘法
- 大数除法
- 大数阶乘
- 输入挂
- 前缀和
- 二分
- 本地预处理
- 尺取
- 枚举
- 坐标离散化
- 分治
- 数列分治
- 树上分治
- 平面分治
- 计算几何
- 凸包
- 点积
- 叉积
- 线段关系
- 皮克定理
- 最近点对
- 数据结构
- 线段树
- 树状数组
- 并查集
- 动态规划
- 基础知识
- 信息学竞赛中的动态规划
- 动态规划初步
- 最长上升子序列(LIS)
- 最长公共子序列(LCS)
- 最大子段和
- 背包问题
- 部分背包
- 0 1 背包
- 完全背包
- 多重背包
- 背包的可行性问题
- 线性DP
- 树形DP
- 区间DP
- 数位DP
- 动态规划优化
- 字符串
- KMP算法
- 拓展KMP
- 字符串Hash
- Manacher算法
- 后缀数组
- Trie树
- 博弈论
- Nim博弈
- Bash博弈
- 斐波那契博弈
- 威佐夫博弈
- SG函数
- 数论
- 整数研究
- 素数判断
- 素数筛选
- 快速幂
- 算数基本定理
- 最大公约数(Gcd)
- 费马小定理
- 扩展欧几里得
- 逆元
- 同余定理
- 组合数学
- 容斥原理
- 抽屉原理
- 卢卡斯(Lucas)
- 卡特兰(Catalan)
- 著名函数
- 欧拉函数
- 莫比乌斯函数
- 线性代数
- 矩阵运算
- 矩阵快速幂
- 图论
- 存图方法
- 邻接矩阵
- 邻接表
- Vector存图
- 链式前向星
- 图的遍历
- 拓扑排序
- 最短路
- Dijkstra算法
- SPFA算法
- Floyed 算法
- 最小生成树
- Prim算法
- Kruskal算法
- 最近公共祖先 (LCA)
- 二分图匹配
- 网络流
- 其他
- 莫队