背包问题(01背包)
以下内容为学习过程的总结,可能有些copy网上内容,请不要在意这些细节!!
01问题的提出:有N件物品和一个容量为V的的背包,N件物品的费用为c[i](i=1--N);
价值为w[i],问将那些物品放入背包使得价值最大且不超过容量?
思路:
01背包的特点是每种物品只有一件,可以选择放或不放,可以用子问题来定义状态,即
f[ i ][ v ]表示第i件物品放入容量为V的背包中可获得最大的价值,则其状态方程可以表示为
f[ i ][ v ]=max(f[i-1], f[i-1][v-c[i]+w[i]);
这个方程就是01背包的全部内容,将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v];如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。
优化方法:
上面的方程式是用二维数组,想想是否可以用一维数组解决问题,所以就有了优化方法
代码如下:
for i=1..N
for v=V..0
f[v]=max{f[v],f[v-c[i]]+w[i]};
对于上面的优化方法是这样的,思路是要求出f[i][v]需要用到肯定是有一个主循环i=1..N,每次算出来二维数组f[i][0..V]的所有值。那么,如果只用一个数组f[0..V],能不能保证第i次循环结束后f[v]中表示的就是我们定义的状态f[i][v]呢?
f[i][v]是由f[i-1][v]和f[i-1][v-c[i]]两个子问题递推而来,能否保证在推f[i][v]时
(也即在第i次主循环中推f[v]时)能够得到f[i-1][v]和f[i-1][v-c[i]]的值呢?
事实上,这要求在每次主循环中我们以v=V..0的顺序推f[v],这样才能保证推f[v]时f[v-c[i]]保存的是状态f[i-1][v-c[i]]的值。
初始化细节:
对于01背包的问题一般有两种问题,
一是问将背包装满时的最优解;
二是背包不装满时的最优解;
对于以上两种的数组初始化是不一样的,第一组要求背包恰好装满着初始化要求f[0]=0;
f[1--n]=-∞ ;
对于第二种这要求全部初始化为0;
初始化的f数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可能被价值为0的nothing“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,它们的值就都应该是-∞了。如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。
补充内容:
01背包是最为基本的背包类型,所以对01背包的变形会有很多种,所以就需要你深刻理解01背包的思想和实现步骤,这几天做题发现了一个变形,以后看到背的变形还会补充;
该题是hdu2955
http://acm.hdu.edu.cn/showproblem.php?pid=2955
这题是一道典型的01背包,但所不同的是需要你用01背包的思想转化问题,题意是一个劫匪想去抢银行,给你一个被抓的概率和几个银行和在这个银行被抓的概率,一看题这不是把概率当背包,套公式就完了,可是你想过概率怎么加吗?
所以这题做法不是将概率作为背包,而是抢的钱作为背包,计算出所有的钱的集合,然后递减求的抢这些钱的概率,然后与你被抓的概率做比较,输出大于该概率的系数,也就是你能抢的钱数,这个变形很有意思,当然会对你对01背包理解更加深刻,做做吧!
代码这里就不给出了,网上别人的博客有,不会可以看看!