文章目录
前言
小结
- 💕完全背包这里有趣的是排列顺序的问题
- 如果要组合,就是先遍历物品再遍历背包,这样就不会有重复的【518零钱兑换】
- 如果要排列,就是先遍历背包再遍历物品,这样就可以有重复的【377. 组合总和 Ⅳ】
完全背包问题
与01背包最大的区别在于物品可以放是无数个;
思路
区别:01背包是倒序的取法,因为只能放一次;那么这里完全背包可以放无数次,明显只能正序遍历;
纯完全背包物品和重量的循环的顺序是可以颠倒的
-
(我的理解)这里递推公式显示只与前面的元素有关【列向更新】,并且遍历重量是从前往后遍历,所以遍历顺序无关;下面给出了横向遍历和列向遍历的例子;
-
而01背包是从后往前遍历,如果后遍历物品的话,从后往前,前面的都还么有处理过呢,都是0,肯定是不对的;
方法一
下面是我自己写的,包括数据读取。
def Completebag(weights,values,bagweight):
dp = [0] * (bagweight+1)
for i in range(len(values)):
for j in range(weights[i],bagweight+1,1):
dp[j] = max(dp[j],dp[j-weights[i]]+values[i])
return dp[bagweight]
if __name__ == "__main__":
first_line = list(map(int,input().strip().split()))
N,V = first_line[0], first_line[1]
weights, values = [], []
for i in range(N):
input_ = list(map(int,input().strip().split()))
weights.append(input_[0])
values.append(input_[1])
# print(weights,values)
result = Completebag(weights,values,V)
print(result)
518. 零钱兑换 II
思路
🎈完全背包问题相较于01背包,最大的区别就是遍历顺序不同,别的几乎都一样
本题思路仍然是二维数组来想:我们先想象横向遍历,从前往后遍历,这就意味着前面的是一个考虑过放过物品i的了。所以递推公式还是一样的两个情况:重量为j的时候,不取物品i和取物品i的两个情况
0 | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 1 | 1 |
2 | 1 | 1 | 2 | 2 | 3 | 3 |
5 | 1 | 1 | 2 | 2 | 3 | 4 |
dp五部曲
- dp含义: 装满背包容量为j的组合数
- 递推公式:前面讲过;dp[j] += dp[j - coins[i]];
- 初始化:dp[0]=1,这里设定为1【有争议的】,非0下标初始化为0
- 遍历顺序:这里必须先写遍历物品,再写遍历背包重量【也就是横向遍历】
- 因为这里是组合而不是排列,如果先遍历物品的话是先看1,再看2,再看5这样,不会有重复的,例如2,1,2 和1,2,2这种,一定是组合,是符合的
- 如果是先写遍历背包重量再写物品的话【纵向遍历】,就会出现2,1,2 和1,2,2的情况;具体原因见下面b站评论,讲得很好
方法一
本题的重点是遍历顺序,必须要先物品再背包重量
初始化为1,一定为1否则不对
class Solution(object):
def change(self, amount, coins):
"""
:type amount: int
:type coins: List[int]
:rtype: int
"""
dp = [0]*(amount+1)
dp[0] = 1
for i in coins:
for j in range(i,amount+1):
dp[j] = dp