zoukankan      html  css  js  c++  java
  • [DP] 背包问题大总结

    @kaike

    1.01背包

    有N件物品和一个容量为C的背包。第i件物品的重量是w[i],价值是v[i]。求解将哪些物品装入背包可使价值总和最大。

    每种物品仅有一件,可以选择放还是不放。

    用f[i][c]表示前i件物品恰好放入容量为c的背包里面,总价值最大。

    f[i][c]=max{f[i-1][c],f[i-1][c-w[i]]+v[i]}

    若不放第i件,就是前i-1件物品放入容量为c的背包里 f[i-1][c]

    若放第i件,把前i-1件物品放入容量为 c-w[i] 的背包里,f[i-1][c-w[i]],总价值加上v[i]。

    f[i][c]是由 f[i-1][c] 和 f[i-1][c-w[i]] 推出来的

    如何在推f[i][c]的时候已知f[i-1][c] 和 f[i-1][c-w[i]]呢

    f[i-1][c]就是不要这件物品,直接去取一个值

    f[i-1][c-w[i]]就是要这件物品,不过你要取空出这个物品重量的最大价值量的值

    由于刚开始时不能出现负值,第一次的时候c不能直接从0开始,需要一个缓冲。

    于是二循环就要从背包容量开始倒推

    注意看

    f[i][c]的值只与f[i-1][c]和f[i-1][c-w[i]]有关,

    如此倒推,完全可以转化为 f[c]=max{f[c],f[c-w[i]]+v[i]}

    外面的f[c]是新值,里面的f[c]是上次循坏的值也就是f[i-1][c]

    f[c-w[i]]同理也是上次循环的值

    这样数组从二维到了一维,可以省空间。

    时间复杂度(n*c)空间复杂度(c)

    最大值当然要从背包满的时候f[c]处取得辣

     

    1 for(int i=1;i<=n;i++)
    2     for(int j=c;j>0;j--)
    3         f[j]=max(f[j],f[j-w[i]]+v[i]);

     

    细节问题

    1.要求恰好装满背包,f[0]=0,f[1-v]=-∞

    2.没要求恰好装满,f[0-v]=0

    若要求恰好装满,则只要容量为0的背包恰好装满,而其他的都是未定义的状态

    若不要求,所有值都有个确定值

     

    2.完全背包问题

    有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

    与01背包不同的是每件可以取无限件

    问题十分棘手啊

    f[i][c]=max{f[i-1][v-k*w[i]]+k*v[i]} 0<=k*w[i]<=v

    若两件物品i、j满足c[i]<=c[j]且w[i]>=w[j],则将物品j去掉,不用考虑。

    看起来小优化并没有优化掉什么复杂的东西,毕竟遇到一些极值还是要奔溃的

    可以从01背包问题获得点启示

    01背包二循环是从c-0开始的,因为他要先预留出来f[c-w[i]]的值

    而完全背包就完全不用考虑这个问题,

    我们从0-c开始循环

    在考虑是否加这个物品的时候,可能正需要一个正好已选入第i个物品的值,所以就正着循环

     

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

     

     

    No matter how you feel, get up , dress up , show up ,and never give up.
  • 相关阅读:
    GDUFE ACM-1050
    hdu-2020
    hdu-2055
    hdu-2734
    GDUFE ACM-1145
    GDUFE ACM-1127
    GDUFE ACM-1126
    GDUFE ACM-1125
    GDUFE ACM-1124
    GDUFE ACM-1123
  • 原文地址:https://www.cnblogs.com/Kaike/p/5950198.html
Copyright © 2011-2022 走看看