背包九讲学习

DD大牛的背包九讲真是神。等我全看懂了回来更博。


upd

如果不是我看错了,那一定是神犇讲的太明白了。

我尝试用几句话概括一下前面部分(P01-P05),每回重新看有些麻烦。

$cost ightarrow花费,value ightarrow价值$


01背包

决策:选或不选,$f[v]$表示v花费可以得到最大价值。则

$forspace v=V...cost$
$f[v]=max(f[v],f[v-cost]+value)$

只能由上一层转移来,所以倒序保证不影响。

想要恰好$V$就只有$v=0$合法即初始化$f[0]=0$,其他为$-inf$。不需要都赋为$0$。

所有问题的基础。$O(nV)$


完全背包

总是记不住这些名字,就当做是“完全随便拿”的背包吧,,,则

$forspace v=cost...V$
$f[v]=max ( f[v],f[v-cost]+value ) $

类似01,可以同层转移,就这样咯。$O(nV)$


多重背包

类似完全背包。加一些限制。是“可以重复多拿”的,但不能太多,每个物品有限制。

想法是拆成二进制的。比如$13=1+2+4+6$这么拆,不要记错了。

楼教主“男人八题”那个单调队列的暂时不会,挖坑。


废话

一些显而易见的贪心。超过$V$的不能选,完全背包里$cost$又大$value$又小的,不去选ta。


混合背包

好像没啥说的,前三个混到一块各做各的该咋做咋做就行。。


二维花费

那就二维状态,类比一下就行。则

$forspace v=V...cost1$

$forspace u=U...cost2$

$f[v][u]=max(f[v][u],f[v-cost1][u-cost2]+value)$

只要不从同一层状态转移过来就好。


写完感觉好傻啊。

所以说重点在于泛化物品咋做。

泛化物品定义成这样:对于你赋给它的每一个花费会获得对应的价值。

更数学化一些,这是一个函数,定义域为$V$,自变量是花费$cost$,函数值是价值$value$。对于每个$cost$都有一个对应的$value$,如果某个$cost$没有定义,我们可以视之为$-inf$。

具体来说,比如01背包中的背包,当且仅当赋给它$cost$值时有函数值$value$,其他为$-inf$。

又如多重背包,我们甚至可以写出解析式:$f[x]=xdiv cost imes value (cost|x)$

当然啦,我们抽象出这样一个定义又有什么用呢?

泛化物品可以做加法!!!

对于两个泛化物品$a,b$,我们把他们加成一个泛化物品$c$,即

$c[v]=max(a[i]+b[v-i])(0leq ileq v)$

复杂度$O(V^2)$。

于是现在再来说刚才没说的分组背包和有依赖的背包。


分组背包

物品分成了$k$组,每组内物品只能选一个或不选。

每组做一次01背包,就可以当做$k$个泛化物品做了。$O(kV^2)$


(树形)依赖背包

依赖显然不会存在环,所以普通的依赖也可以转成树形。

然后通法就是:儿子当做泛化物品,则父亲是儿子之和,递归处理之。

这里会补上一个代码。


至此我对背包九讲的理解结束了!!现在看起来真的不是很难懂的东西但却十分巧妙,尤其是用函数的思想将物品转化成泛化物品,让我不得不佩服DD大牛%%%。最后一讲我没有细看,如果有时间我应该会回来更博写一下。


upd

树形背包有$O(NM)$做法的啊。所以上面的代码就不补了(已经用那种做法水掉CTSC1998选课了,时间上差了好多顿时不想贴那个的代码了)。

$dp[i][j]$表示选择了节点 $i$ (及其所有祖先节点) (即根节点到 $i$ 的路径——记作 $Pi$ 上的所有节点),此外再在 $Pi$ 的左侧和子树 $i$ 中选择总体积不超过 $j$ 的物品的最大价值。

void dfs(int u,int f,int cost)
{
    if(cost<=0)return ;
    for(int i=0;i<e[u].size();i++){
        int v=e[u][i];
        if(v==f)continue;
        for(int j=0;j<=cost;j++)dp[v][j]=dp[u][j];
        dfs(v,u,cost-b[v]);
        for(int j=b[v];j<=cost;j++)dp[u][j]=max(dp[u][j],dp[v][j-b[v]]+a[v]);
    }
}
原文地址:https://www.cnblogs.com/orzzz/p/7743056.html