======背包问题 by iuiou======
所谓背包问题,有一个非常经典的模型:现在有n个物品,第i个物品有一个权值$e_i$,有一个费用$w_i$,每种物品只能选取1次,现你手中
只有m元钱,问如何选取物品才会使手中物品的权值达到最大?
简要分析:这种有代价,有选择然后取最值的题目,一般只有两种思路,一种是贪心,一种是动态规划。两者的区别我一直非常迷惑,知道看到一个大佬多写的文章。总的来说,贪心注重由固定的规律(多是能证明或者显而易见)由**局部**解推出最终解,**每一步都能保证前一步的答案是最优的**,而动态规划,是由每种状态的转移,来从**每一个比当前小的状态**转移出大状态的解。并不能保证前一个状态的结果是最优的,所以要遍历所有情况。其实就相当于找一种方法来遍历所有情况,而其核心在于初始化和转移。
回到这题,既然放在动态规划肯定是动态规划啦,这个题目明显找不到一个确定的谈心策略,能保证每一步都是最优的,至少我看不出来,所以考虑动态规划。
**核心转移**:$dp[m]=\max(dp[m],dp[m-w_i]+e_i)$
上面这个式子太显然了没啥好说的,$dp[i]$表示i元钱能得到的最大权值,然后有花费和赚。
循环:
for(int i=1;i<=n;i++)
{
for(int j=v;j>=a[i];j--)
{
dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
}
}
上面是01背包,每个物品选一次。
*可重背包:只需要改成
for(int i=1;i<=n;i++)
{
for(int j=a[i];j<=v;j--)
{
dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
}
}
*多重背包:即限定了每种的个数,可以考虑转化为01背包,把相同的看成一个,还可以采用二进制分组的方法,简化复杂度。
*分组背包:有许多组,每组有若干个,每组只能选一个。最外面枚举组别,考虑在最里面一层再加入一个循环判断选这个组哪个物品。
*有依赖背包:即选一个必选依附的那一个,转化状态即可,将不同的状态看成物品,即加入选b或选c就要选a,可以直接转化为只选a,只选a和b,只选a和c,选则a,b,c这样四种情况,分别看作一种物品,做分组背包即可。
背包问题大致就上面这些,还有都是这些问题的变式,也大致基于上面所说的核心转移方程。