01背包
多种物品,每种物品只有一个.求能获得的最大总价值.
我们考虑是否选择第i件物品时,是需要考虑前i-1件物品对答案的贡献的.
分析
如果我们不选择第i件物品,那我们就相当于是用i-1件物品,填充了体积为v的背包所得到的最优解.
而我们选择第i件物品的时候,我们要得到体积为v的背包,我们需要通过填充用i-1件物品填充得到的体积为v-c[i]的背包得到体积为v的背包.
//请保证理解了上面加粗的字再往下看.
所以根据上面的分析,我们很容易设出01背包的二维状态
f[i][v]f[i][v]代表用i件物品填充为体积为v的背包得到的最大价值.
从而很容易的写出状态转移方程
f[i][v]=max(f[i-1][v],f[i-1][v-c[i]]+w[i])f[i][v]=max(f[i−1][v],f[i−1][v−c[i]]+w[i])
状态转移方程是如何得来的?
对于当前第ii件物品,我们需要考虑其是否能让我们得到更优解.
显然,根据上面的话
我们选择第i件物品的时候,我们要得到体积为v的背包,我们需要通过填充用i-1件物品填充得到的体积为v-c[i]的背包得到体积为v的背包.
我们需要考虑到v-c[i]v−c[i]的情况.
当不选当前第ii件物品的时候,就对应了状态转移方程中的f[i-1][v]f[i−1][v],
而选择的时候就对应了f[i-1][v-c[i]]+w[i]f[i−1][v−c[i]]+w[i].
Q:是不是在状态转移方程中一定会选择当前i物品?
A:不会
我们考虑一个问题.
如果一个体积为5的物品价值为10,而还有一个体积为3的物品价值为12,一个体积为2的物品价值为8.显然我们会选择后者.
这样我们的状态转移方程中就不一定会选择i物品。
其实最好地去理解背包问题的话,还是手跑一下这个过程,会加深理解。
代码写法↓
for(int i=1;i<=n;i++)//枚举 物品
for(int j=1;j<=V;j++)//枚举体积
//这个位置是可以正序枚举的. qwq
//一维01背包必须倒叙 emmm
//这个没错a emmm
//采药可以过的 qwq
if(j>=c[i])
f[i][j]=max(f[i-1][j],f[i-1][j-c[i]]+w[i]);//状态转移方程.
else f[i][j]=f[i-1][j].
//上面的if语句是判断当前容量的背包能否被较小体积的背包填充得到.
//显然 如果j-c[i]<0我们无法填充
//(谁家背包负的体积啊 (#`O′)
但是二维下的01背包我们还是无法满足,怎么办?
考虑一维如何写!
仔细观察会发现,二维状态中,我们的状态每次都会传递给i(就是说我们的前几行会变得没用.)
这就给了我们写一维dp的机会啊
所以我们理所当然地设状态f[i]f[i]代表体积为i的时候所能得到的最大价值.
则,一维的状态转移方程是f[j]=max(f[j],f[j-c[i]]+w[i]).f[j]=max(f[j],f[j−c[i]]+w[i]).
容易发现的是,我们的f[i]f[i]只会被i以前的状态影响.
如果我们顺序枚举,我们的f[i]f[i]可能被前面的状态影响.
所以我们考虑倒叙枚举,这样我们的f[i]f[i]不会被i以前的状态影响,而我们更新的话也不会影响其他位置的状态.
(可以手绘一下这个过程,应该不是很难理解.)
或者来这里看看(可能图画的有点丑了
代码写法↓
for(int i=1;i<=n;i++)//枚举 物品
for(int j=V;j>=c[i];j--)//枚举体积
f[j]=max(f[j],f[j-c[i]]+w[i]);//状态转移方程.
//应该不是很难理解.
小结
01背包问题是背包问题中最基础,也是最典型的问题.其状态转移方程也是基础,更可以演变成其他背包的问题.
请保证看懂之后再向下看.
完全背包
for(int i=1;i<=n;i++)//枚举物品
for(int j=c[i];j<=V;j++)//枚举体积.注意这里是顺序/
f[j]=max(f[j],f[j-c[i]]+w[i]);//状态转移.
t,m1=list(map(int,input().split()))
yao=[None,]
for i in range(m1):
q,q1=list(map(int,input().split()))
yao.append({'w':q,'v':q1})
m=[[0]*(t+1)for _ in range(m1+1)]
dp=[0]*(t+1)
if m1==1:
print(t//yao[1]['w']*yao[1]['v'])
else:
#二维
# for i in range(1,m1+1):
# for j in range(yao[i]['w'],t+1):
# if yao[i]['w']>j:
# m[i][j]=m[i-1][j]
# else:
# m[i][j]=max(m[i-1][j],m[i][j-yao[i]['w']]+yao[i]['v'])
# print(m[m1][t])
#一维
for i in range(1, m1 + 1):
# for j in range(t,yao[i]['w']-1,-1):
for j in range(yao[i]['w'] , t+1):
dp[j]=max(dp[j],dp[j-yao[i]['w']]+yao[i]['v'])
print(dp[t])
print(dp)
多重背包