写代码的第三十二天
开始完全背包了。。。。
01还没整明白
完全背包
思路
1、和01背包的第一个区别在于,他的每个物品都是可以重复使用的;
2、根据1的情况,代码中的两层for循环中的第二层循环在01背包的时候一直是倒叙的,为了只让每个物品用一次,那么在完全背包中就不用到序了,因为每个物品可以用多次,所以直接正序就可以了;
3、先遍历物品还是先遍历weight都可以!
简单来说就是01背包的二维情况是ij位置的value是由上方和左上方的值决定的,但是完全背包可以看作是只由左侧的数值决定。
正确代码:下面的主函数输入写了好久没写对,真无语啊。。。
def test_2_wei_bag_problem1(weight, value, bagWeight):
dp = [0] * (bagWeight + 1)
for i in range(len(weight)): # 遍历物品
for j in range(weight[i], bagWeight + 1): # 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
return dp[bagWeight]
if __name__ == "__main__":
# 输入研究材料的种类和行李空间
N, V = map(int, input().split())
weight = []
value = []
# 输入每种研究材料的重量和价值
for _ in range(N):
w, v = map(int, input().split())
weight.append(w)
value.append(v)
result = test_2_wei_bag_problem1(weight, value, V)
print(result)
518. 零钱兑换 II
思路
硬币数量都不止一个,所以是完全背包问题。
解决问题1:dp[j]代表什么?数组中的数字加和为j的时候有dp[j]种组合方式。
解决问题2:递推公式是什么?这个是组合的个数,所以可以回想爬楼梯以及昨天做的目标和这道题,所以最后的递推公式是dp[j] += dp[j-coins[i]],
解决问题3:dp数组的初始化是什么?和之前的题一样dp[0]的初始化为1(其实这里我是根据之前的题得出的,但是之前的题那个例子不太适用于这里)。我理解的dp[0]的定义是当背包容量为0的时候有1种方法,因为只有不符合条件的时候才返回值为0,所以只要有符合条件的时候就返回1。
解决问题4:遍历顺序是什么?如果先遍历物品后遍历weight,那么先遍历的是物品,那么物品一定是按照顺序放进去的,先是第一个,然后是第二个,那么就是组合,只有顺序[1,2,…];如果是先遍历weight后遍历物品的话,那么物品的顺序在每次遍历weight的时候都是从第一个开始的,所以顺序可以是[1,2]或者[2,1]。
解决问题5:输出dp数组。
正确代码:啊啊啊啊啊啊啊我自己写出来啦啦啦啦啦,别管是理解多少,先有答题思路了!!!!!!!好开心啊啊啊啊啊!!!!
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [0] * (amount + 1)
dp[0] = 1
for i in range(len(coins)):
for j in range(coins[i],amount+1):
dp[j] += dp[j-coins[i]]
return dp[amount]
377. 组合总和 Ⅳ
思路
在本题中物品就是nums数组的下标,weight和value都是nums数组的值,target为背包容量。
需要注意!!!这个题是有顺序的!!!!!
解决问题1:dp[j]数组的含义是什么?满足背包容量为j的排列个数为dp[j]。
解决问题2:递推公式是什么?还是问组合情况的,还是考虑像爬楼梯那种递推公式,所以为dp[j] += dp[j-nums[i]]
解决问题3:dp数组初始化为什么?和之前的一样dp[0] =1
解决问题4:遍历顺序是什么?如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
解决问题5:输出dp数组。
错误第一版:先遍历背包,背包容量0已经被定义的,所以要从1开始 ;习惯了先遍历物品后遍历背包,那么本题翻转过来就忘记了j-nums[i]这行代码是需要判断的,不然会越界的。
class Solution:
def combinationSum4(self, nums: List[int], target: int) -> int:
dp = [0] * (target + 1)
dp[0] = 1
for j in range(target+1):
for i in range(len(nums)):
dp[j] += dp[j-nums[i]]
return dp[target]
正确代码:
class Solution:
def combinationSum4(self, nums: List[int], target: int) -> int:
dp = [0] * (target + 1)
dp[0] = 1
for j in range(1,target+1):
for i in range(len(nums)):
if j >= nums[i]:
dp[j] += dp[j-nums[i]]
return dp[target]
70. 爬楼梯 (进阶)
思路
之前的题是每次只能走一个台阶或者两个台阶,本题是每次可以最多走m个台阶,根据之前的递推公式可以知道dp[i] = dp[i-1]+dp[i-2],这里面的dp[i]数组代表走到i阶的时候有dp[i]种方法,1和2代表每次可以背包的重量,也就是第二层循环中代表weight的j,那么本题的dp数组定义也是一样的,所以dp[i] = dp[i-1]+dp[i-2]+…+dp[i-m]其实也就可以写作dp[i] +=dp[i-j];同时本题的先走1阶再走两阶和先走两阶再走一阶得到的路线方法是不同的,所以是排列,那么就应该先遍历weight,再遍历物品。
正确代码:
def climbing_stairs(n,m):
dp = [0] * (n + 1)
dp[0] = 1
for j in range(1,n+1):
for i in range(1,m+1):
if j >= i:
dp[j] += dp[j-i]
return dp[n]
if __name__ == '__main__':
n,m = list(map(int,input().split(' ')))
print(climbing_stairs(n,m))