Day 46 | 动态规划 08

56 阅读2分钟

139. 单词拆分

def wordBreak(self, s: str, wordDict: List[str]) -> bool:
    # 单词就是物品,字符串s就是背包,单词能否组成字符串s,就是问物品能不能把背包装满。
    # 本题求的是排列数 因为要考虑顺序 
    # 求排列数就是外层for遍历背包,内层for循环遍历物品
    dp = [False]*(len(s) + 1)
    dp[0] = True
    # 遍历背包
    for j in range(1, len(s) + 1):
        # 遍历单词
        for word in wordDict:
            if j >= len(word):
                dp[j] = dp[j] or (dp[j - len(word)] and word == s[j - len(word):j])
    return dp[len(s)]

多重背包

有N种物品和一个容量为V的背包。第i种物品最多有Mi件可用,每件耗费的空间是Ci ,价值是Wi.

不同点是每个物品有自己的数量Mi

每件物品最多有Mi件可用,把Mi件摊开,其实就是01背包问题。

时间复杂度:O(m × n × k),m:物品种类个数,n背包容量,k单类物品数量

或者再加入一层循环表示物品数量的迭代

随想录代码

def test_multi_pack1():
    '''版本一:改变物品数量为01背包格式'''
    weight = [1, 3, 4]
    value = [15, 20, 30]
    nums = [2, 3, 2]
    bag_weight = 10
    for i in range(len(nums)):
        # 将物品展开数量为1
        while nums[i] > 1:
            weight.append(weight[i])
            value.append(value[i])
            nums[i] -= 1
    
    dp = [0]*(bag_weight + 1)
    # 遍历物品
    for i in range(len(weight)):
        # 遍历背包
        for j in range(bag_weight, weight[i] - 1, -1):
            dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
    
    print(" ".join(map(str, dp)))

def test_multi_pack2():
    '''版本:改变遍历个数'''
    weight = [1, 3, 4]
    value = [15, 20, 30]
    nums = [2, 3, 2]
    bag_weight = 10

    dp = [0]*(bag_weight + 1)
    for i in range(len(weight)):
        for j in range(bag_weight, weight[i] - 1, -1):
            # 以上是01背包,加上遍历个数
            for k in range(1, nums[i] + 1):
                if j - k*weight[i] >= 0:
                    dp[j] = max(dp[j], dp[j - k*weight[i]] + k*value[i])

    print(" ".join(map(str, dp)))

背包总结

dp数组存放的值就是结果

01背包vs完全背包

求组合数就是外层for循环遍历物品,内层for遍历背包

求排列数就是外层for遍历背包,内层for循环遍历物品