完全背包详解
-
大家应该都知道完全背包这一种题型,是dp的一种类型,其实dp说白了就是“一直优秀”,就是把所走的每一步都当做最优的,然后在这个基础上让他更加优秀。
-
上例子:
题目描述
LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是 LiYuxiang,你能完成这个任务吗?
此题和原题的不同点:
每种草药可以无限制地疯狂采摘。
药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了! -
题解:和01背包相比其实就是多了无限制采药。
- 01背包再加一个k循环(取每种的个数)
- 二维数组获取 f[i][j]=max(f[i][j],f[i][j-w[i]+v[i])
解:其实就是拿现在的和之前已经推出的最优比。 - 一维数组获取 f[j]=max(f[j],f[j-w[i]]+v[i])
解:同理二维
-
我们来看一下一维的每层(每层在这里指每个种类)循环后的dp数组的值
代码:for(int i=1;i<=n;i++) for(int j=w[i];j<=m;j++){ dp[j]=max(dp[j],dp[j-w[i]]+v[i]); for(int z=0;z<=j;z++){ printf("%d ",dp[z]); } printf("\n"); printf("%d\n",j); printf("\n"); }
如图,我们着重看一下,种类变化后的输出(这个是由第二个(5,2)变为第三个(18,6))
第二重循环中为什么j从w[i]开始呢,因为,有w[i]才能装下,之前都装不下,是其他情况中的最优。
进入下一个种类时,f[j]=max(f[j],f[j-w[i]]+v[i]),f[j]是从前几个种类得到的最优,f[j-w[i]]+v[i]是返回到只选择了(j-w[i])的时间时的最优。
比如我现在t=18 目前的最优是10 而现在选择的是(18,11)
设此时f[j]=f[18]=10
则f[j-w[i]]+v[i]=f[18-18]+11=f[0]+11=11 f[0]是之前所算出最优时的值。
补:i和j的含义特别重要,其中i是第几个种类,用于得到v[i],w[i],j则是已用的时间,用于得到dp数组。