背包dp小结

昨晚太困了,于是就没有写,今天补上。

首先是01背包,每个物品最多选一次。

方程很简单,f[i][j]表示前i个物品花费j的空间的最大价值。

f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]) (j>=v[i])

然后,我们发现第一维是没有用的,就把它去掉,为了保证状态的合理转移,我们第二重循环要倒序循环(为什么呢?)。

然后是完全背包,每个物品随便选。

方程也很简单,f[i][j]=max(f[i-1][j],f[i][j-v[i]]+w[i])(j>=v[i])。

咦,是不是很相似,那么我们也尝试把第一维去掉,为了保证状态的合理转移,我们第二重循环要顺序循环(为什么呢?)。

我们发现01背包和完全背包的唯一区别就是第二重循环的循环顺序,01背包要倒序循环就是为了要避免在花费为

j的状态之前已经选过了第i个物品,而多重背包恰恰是可以在选过第i个物品后继续选择第i个物品。

之后是多重背包,每个物品有上限。

方程也很简单,f[i][j]=max(f[i-1][j-k*v[i]]+k*w[i])(j>=v[i])(0<=k<=c[i])

但是这个方程并不漂亮,它的复杂度并不好看,所以我们考虑两种优化模式。

第一种,物品拆分,将第i个物品(v[i],w[i],c[i]),拆成(1*v[i],1*w[i],1)(2*v[i],2*w[i],1)(4*v[i],4*w[i],1)……

(2^(k-1)*v[i],2^(k-1)*w[i],1)((c[i]-2^k)*v[i],(c[i]-2^k)*w[i],1),其中k是时c[i]-2^k>0的最大的整数。

这样做很显然是正确的(为什么呢?),我们可以随意证明一下(分两种情况,取的数量大于等于2^k和小于2^k)。

第二种,方法是单调队列优化,论文里并没有讲。

考虑第i个背包,我们把所有状态分成w[i]类,分别为模w[i]的剩余系,这些状态之间转移似乎不干扰的,只能是类内转移,那么不妨有一个单调队列来维护一个最大值,当队头超过了可以取的次数,就把它出队,然后每次入队的时候要入F[j*v+d]- j*w,为什么呢,因为我们最后取的时候比如我们在f[k*v+d]是取f[j*v+d]的决策,那么f[k*v+d]=f[j*v+d]+(k-j)*w=(f[j*v+d]-j*w)+kw,就是这个样子,所以入队的时候把所有带j的都一起入进去才行。

然后是混合背包,其实有了前面的基础,这个非常简单。

就是看一看每一个背包是哪一种类型,然后按照那种类型的背包进行转移。

二维背包的话,非常简单,会写方程就好了。

分组背包,分成k个组,每一个组只能选一个。

按每组讨论,那么其实和01背包是一样的,因为01背包就是相当于n个组嘛。

有依赖的背包等等,这一些都可以用泛化背包的思想解决,至于泛化背包是什么吗,自己看论文吧。

貌似树形背包,就是每次把父亲和儿子进行一次泛化背包的合并,咦,貌似是O(nV)的。

NOIP应该考不到那么难吧,那么NOIP集训呢?!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值