【leetcode】背包问题汇总

版权声明:转载请注明 https://blog.csdn.net/u013166817/article/details/85449218

详细解析参考“背包九讲”:https://github.com/tianyicui/pack

目录

1. 背包问题 I —— 0-1背包无价值

2. 背包问题II —— 0-1背包有价值

3. 背包问题III —— 完全背包问题

小结1

4. 背包问题IV / V —— 求方案数

5. 背包问题VII —— 多重背包问题

6. 多重背包可行性解

7. 换零钱问题

 

扫描二维码关注公众号,回复: 4776936 查看本文章

1. 背包问题 I —— 0-1背包无价值

0-1背包问题,无价值:https://www.lintcode.com/problem/backpack/description

问题描述:Given n items with size Ai, an integer m denotes the size of a backpack. How full you can fill this backpack?

解析:

递推公式:dp[i][j] = max(dp[i-1][j-A_i] + A_i, dp[i-1][j])

dp[i][j]:前i个物品放入容量为j的背包的最大重量;

dp[i-1][j-A_i] + A_i:放入第i个时的重量;

dp[i-1][j]:不放第i个时的重量;

第一层循环 i:0~n

第二层循环 j:m ~ Ai,倒序是因为每个物品只能用一次。

可简化成一位数组。

class Solution:
    """
    @param m: An integer m denotes the size of a backpack
    @param A: Given n items with size A[i]
    @return: The maximum size
    """
    def backPack(self, m, A):
        n = len(A)
        if n <= 0 or m <= 0:
            return 0
        dp = [0 for _ in range(m+1)]
        for i in range(n):
            for j in range(m,A[i]-1,-1):
                dp[j] = max(dp[j-A[i]] + A[i], dp[j])
        return dp[-1]

2. 背包问题II —— 0-1背包有价值

0-1背包问题有价值:https://www.lintcode.com/problem/backpack-ii/

问题描述:

Given n items with size Ai and value Vi, and a backpack with size m. What's the maximum value can you put into the backpack?

Example:

Given 4 items with size [2, 3, 5, 7] and value [1, 5, 2, 4], and a backpack with size 10. The maximum value is 9.

思路:同上

class Solution:
    """
    @param m: An integer m denotes the size of a backpack
    @param A: Given n items with size A[i]
    @param V: Given n items with value V[i]
    @return: The maximum value
    """
    def backPackII(self, m, A, V):
        # write your code here
        n = len(A)
        if m <= 0 or n <= 0:
            return 0
        dp = [0 for _ in range(m + 1)]
        for i in range(n):
            for j in range(m,A[i]-1,-1):
                dp[j] = max(dp[j-A[i]]+V[i], dp[j])
        return dp[m]

3. 背包问题III —— 完全背包问题

完全背包问题,有价值无限个数:https://www.lintcode.com/problem/backpack-iii/description

问题描述:

Given n kind of items with size Ai and value Vi( each item has an infinite number available) and a backpack with size m. What's the maximum value can you put into the backpack?

Example:

Given 4 items with size [2, 3, 5, 7] and value [1, 5, 2, 4], and a backpack with size 10. The maximum value is 15.

思路:

递推公式:dp[i][j] = max(dp[i][j-A_i] + V_i, dp[i-1][j])​​​​​​

dp[i][j]:同理;

dp[i][j-A_i] + V_i:放入第i个物品时,不管上一次放没放入过该物品;

dp[i-1][j]:不放入第i个物品时;

第一层循环i:0~n

第二层循环j:Ci~m,正向,因为不用顾忌每个物品只能放一次。

class Solution:
    """
    @param A: an integer array
    @param V: an integer array
    @param m: An integer
    @return: an array
    """
    def backPackIII(self, A, V, m):
        # write your code here
        n = len(A)
        if n <= 0 or m <= 0:
            return 0
        dp = [0 for _ in range(m+1)]
        for i in range(n):
            for j in range(A[i], m+1):
                dp[j] = max(dp[j-A[i]] + V[i], dp[j])
        return dp[-1]

小结1

0-1背包问题 vs 完全背包问题,实质性区别在于第二层循环一个是倒序,一个是正序:

4. 背包问题IV / V —— 求方案数

0-1 背包问题,返回方案数:https://www.lintcode.com/problem/backpack-v/description

完全背包问题,返回方案数:https://www.lintcode.com/problem/backpack-iv/description

以完全背包问题为例:

Given n items with size nums[i] which an integer array and all positive numbers, no duplicates. An integer target denotes the size of a backpack. Find the number of possible fill the backpack.

Each item may be chosen unlimited number of times

Example:

Given candidate items [2,3,6,7] and target 7,

A solution set is: 
[7]
[2, 2, 3]

return 2

解析:

将完全背包问题里面的max改为sum,且初始化时将dp[0] 设为1;

class Solution:
    """
    @param nums: an integer array and all positive numbers, no duplicates
    @param target: An integer
    @return: An integer
    """
    def backPackIV(self, nums, target):
        # write your code here
        n = len(nums)
        if n <= 0 or target < 0:
            return 0
        dp = [0 for _ in range(target+1)]
        dp[0] = 1
        for i in range(n):
            for j in range(nums[i],target+1):
                dp[j] = dp[j - nums[i]] + dp[j]
        return dp[-1]

5. 背包问题VII —— 多重背包问题

多重背包问题,每个物品有限个个数,求最大价值:https://www.lintcode.com/problem/backpack-vii/description

问题描述:

Assume that you have n yuan. There are many kinds of rice in the supermarket. Each kind of rice is bagged and must be purchased in the whole bag. Given the weightprice and quantity of each type of rice, find the maximum weight of rice that you can purchase.

Example:

Given:
n = 8
prices = [2,4]
weight = [100,100]
amounts = [4,2]

Return:400

基本思路:

假设有N类物品,每个物品有M_i个,则可以转换成 \sum_{i=1}^N M_i 个0-1背包问题。则时间复杂度为:O(V \sum M ),,V为背包容量,M是每个物品的个数的集合。

进阶思路:

可以将每类物品分成 k = \left \lfloor log_2 M_i \right \rfloor + 1 个,每个对应一个新的价值和重量,然后转化为\sum_{i=1}^N k_i个0-1 背包问题,则时间复杂的降为:O(V \sum log_2M )

import math
class Solution:
    """
    @param n: the money of you
    @param prices: the price of rice[i]
    @param weight: the weight of rice[i]
    @param amounts: the amount of rice[i]
    @return: the maximum weight
    """
    def backPackVII(self, n, prices, weight, amounts):
        #将每一类物品转化为k个子物品,求得对应的价钱,重量,转化成0-1背包问题
        #先生成新的物品集合
        new_prices = []
        new_weight = []
        for i in range(len(amounts)):
            k = int(math.log(amounts[i],2))+1
            coefs = [2**i for i in range(k - 1)]
            coefs.append(amounts[i] - 2**(k-1) + 1)
            for item in coefs:
                new_prices.append(item*prices[i])
                new_weight.append(item*weight[i])
        #0-1背包问题
        dp = [0 for _ in range(n+1)]
        for i in range(len(new_prices)):
            for j in range(n, new_prices[i]-1, -1):
                dp[j] = max(dp[j-new_prices[i]] + new_weight[i], dp[j])
        return dp[-1]
    

6. 多重背包可行性解

多重背包问题求可行性解的个数:https://www.lintcode.com/problem/backpack-viii/description

问题描述:

Give some coins of different value and their quantity. Find how many values which are in range 1 ~ n can these coins be combined

Example

Given:
n = 10
value = [1,2,4]
amount = [2,1,1]

Return: 8
They can combine all the values in 1 ~ 8

思路: 

class Solution:
    """
    @param n: the value from 1 - n
    @param value: the value of coins
    @param amount: the number of coins
    @return: how many different value
    """
    #多重背包可行性问题 O(VN)
    def backPackVIII(self, n, value, amount):
        # write your code here
        dp = [-1 for _ in range(n+1)]
        dp[0] = 0
        for i in range(len(value)):
            for j in range(n+1):
                if dp[j] >= 0:
                    dp[j] = amount[i]
                else:
                    dp[j] = -1
            for j in range(n-value[i]+1):
                if dp[j] > 0:
                    dp[j+value[i]] = max(dp[j+value[i]], dp[j] - 1)
            
        return n - dp.count(-1)

7. 换零钱问题

即完全背包问题求解最小的使用个数。:https://www.lintcode.com/problem/coin-change/description

问题描述:

You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.

Example:

Given coins = [1, 2, 5], amount = 11
return 3 (11 = 5 + 5 + 1)

Given coins = [2], amount = 3
return -1.

Notice:

You may assume that you have an infinite number of each kind of coin.

思路:完全背包问题,转换成最小组合数。

class Solution:
    """
    @param coins: a list of integer
    @param amount: a total amount of money amount
    @return: the fewest number of coins that you need to make up
    """
    def coinChange(self, coins, amount):
        # write your code here
        dp = [float('inf') for _ in range(amount+1)]
        dp[0] = 0
        for i in range(len(coins)):
            for j in range(coins[i],amount+1):
                dp[j] = min(dp[j-coins[i]] + 1, dp[j])
        if dp[-1] < float('inf'):
            return dp[-1]
        else:
            return -1

猜你喜欢

转载自blog.csdn.net/u013166817/article/details/85449218
今日推荐