01背包问题

【题目描述】有n个重量和价值分别为wi,vi的物品。从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值。

【限制条件】

  • 1≤n≤100
  • 1≤wi,vi≤100
  • 1≤W≤10000

【输入样例】第一行为n值,第二行为n个w值,第三行为n个v值,第四行为W值。

4
2 1 3 2
3 2 4 2
5

【输出样例】W(选择第0、1、3号物品)


 1. 先用最朴素的方法,针对每个物品是否放入背包进行搜索试试看。

n=int(input())
w=list(map(int,input().split()))
v=list(map(int,input().split()))
W=int(input())

# 递归,从第i个物品开始挑选总重小于j的部分
def rec(i,j):
    if i==n:  # 已经挑选完毕
        return 0
    elif j

01背包问题_第1张图片

2. 针对这个样例,rec的递归调用情况如图所示。可以看到,rec以(3,2)为参数调用了两次,浪费了一些时间。因此,我们可以通过记忆化数组,把第一次调用时的结果记录下来,以避免重复计算。

n=int(input())
w=list(map(int,input().split()))
v=list(map(int,input().split()))
W=int(input())

# 记忆化数组
dp=[[-1 for i in range(W+1)] for j in range(n+1)]

# 递归,从第i个物品开始挑选总重小于j的部分
def rec(i,j):
    if dp[i][j]>=0:
        return dp[i][j]
    ans=-1  # 初始化
    if i==n:  # 已经挑选完毕
        ans=0
    elif j

通过记忆化数组,时间复杂度从O(2^n)降到了O(nW)。但是在初始化数组时,要特别注意它的容量要足够大。

3. 接下来,我们将记忆化数组写成递推式。

01背包问题_第2张图片

 如上所示,不用写递归函数,直接利用递推式将各项的值计算出来,简单地用二重循环也可以解决这一问题。这便是动态规划法(DP)。01背包问题_第3张图片

n=int(input())
w=list(map(int,input().split()))
v=list(map(int,input().split()))
W=int(input())

# 记忆化数组
dp=[[0 for i in range(W+1)] for j in range(n+1)]

for i in range(n-1,-1,-1):
    for j in range(0,W+1):
        if j

动态规划法的复杂度也是O(nW),但是简洁了很多。解决问题时可以按照如上方法从记忆化搜索出发推导出递推式,熟练后也可以直接得出递推式。

你可能感兴趣的:(算法,动态规划)