背包dp

1. 例题1:0101 背包模板/采药

同样的思考方式:状态是什么,方程是什么
状态:dpi,jdp_{i,j} 表示在 ii 个物品中用 jj 元选的最优解
方程:dpi,jdp_{i,j} 可以用 iwii-w_i 元来换取 viv_i 的最优解
初始值:dpi,0=0dp_{i,0}=0
代码:

for(int i=1;i<=n;i++) dp[i][0]=0;
for(int i=1;i<=n;i++)
        for(int j=w[i];j<=m;j++)
            dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);

但是有定义有二维,考虑优化一层。
方法一:交替dp
我们发现,只需要存 dpi1dp_{i-1} 就行了。
所以可以开 dp[2][n];
每一次存就可以了。
核心代码:

int now=0,old=1;
for(int i=1;i<=n;i++)
{
        swap(now,old);
        for(int j=w[i];j<=m;j++)
            自己想方程;
}

方法二:滚动数组
刚刚还是用了二维啊!!!
似乎一维只需要去第一维便可以呀!!!

for(int i=1;i<=n;i++)for(int j=w[i];j<=t;j++)f[j]=max(f[j],f[j-w[i]]+v[i]);

然后发现你挂了(不会有人复制了吧)
   i  注意 \color{#00B8D4} \rule{2pt}{44pt} \color{#E5F8FB} \rule[24pt]{200pt}{20pt} \color{#e8e8e8}\rule{0.5pt}{44pt} \color{#f5f5f5}\rule{0.5pt}{44pt} \color{#fafafa}\rule{0.5pt}{44pt} \kern{-200pt}\kern{-1.5pt} \color{#bfbfbf}\rule[0pt]{200pt}{0pt}\kern{-200pt} \color{#d6d6d6}\rule[-0.5pt]{200pt}{0pt}\kern{-200pt} \color{#ececec}\rule[-1pt]{200pt}{0pt}\kern{-200pt} \color{#f8f8f8}\rule[-1.5pt]{200pt}{0pt}\kern{-200pt} \color{black} \raisebox{24pt}{ \raisebox{6pt}{ \kern{-1pt} \color{#00B8D4}\large{\kern{2pt}\bf{i}\kern{5.5pt}} \raisebox{1.5pt}{ \color{#404040}\footnotesize \kern{-4pt}\sf\bf{注意} }}}\kern{-200pt}.  dp的另外一个问题:枚举方向\kern{0pt}\raisebox{10pt}{\footnotesize\sf{ dp的另外一个问题:枚举方向}}

你会发现,只需要稍微改变一下顺序就可以了。不理解的在纸上写一下dp过程。

for(int i=1;i<=n;i++)
        for(int j=t;j<=w[i];j--)
            f[j]=max(f[j],f[j-w[i]]+v[i]);

2. 例题2:完全背包模板/疯狂的采药

完全背包和 0101 背包完全相反,刚刚你写错的代码就是AC正解……

for(int i=1;i<=n;i++)
        for(int j=w[i];j<=t;j++)
            f[j]=max(f[j],f[j-w[i]]+v[i]);

3. 例题3:多重背包/迪奥娜的难题(数据未完成)

这里可以先自己思考一下,代码如下:

for(int i=1;i<=n;i++)
        for(int j=0;j<=v;j++)
            for(int k=0;k<=s[i]&&k*c[i]<=j;k++)
                dp[i][j]=max(dp[i][j],dp[i-1][j-kc[i]]+kw[i]);

but 这样子dp数组根本存不下来,我们得了解一下二进制优化:
首先,我们可以将它分成 ai\sum a_i 份,接着并可以 0101 背包
这样子时间复杂度变为了 O(nAm)O(nAm),还是会 T。
我们可以使用二进制优化。
因为 n=1+2+4+8++2k1+2k+Kn=1+2+4+8+\cdots+2^{k-1}+2^k+K,所以我们拆的时候就这么拆就行了

4. 例题4:混合背包/樱花

似乎很难诶...
stop,不就是把三种dp结合在一起吗? 01背包可以看成只有一个的多重背包。
伪代码如下:

for(int i=1;i<=n;i++)
        if(t[i]==0)
            完全背包
        else
            多重背包

代码是不可能给你的...

posted @ 2023-09-05 21:03  sLMxf  阅读(7)  评论(0)    收藏  举报  来源