昨晚太困了,于是就没有写,今天补上。
首先是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集训呢?!