zoukankan      html  css  js  c++  java
  • 0/1背包

    内容参考书籍《算法竞赛入门到进阶》

      0/1背包是最经典的DP问题,没有之一。

    背包问题:有多个物品,重量不同、价值不同,以及一个容量有限的背包,选择一些物品装到背包中,问怎么才能使装进背包的物品总价值最大

    如果每个物体可以切分,则是一般背包问题,使用贪心法。例如吃自助餐,要使吃到肚子里的东西价值最大,只需要从最贵的食物吃起即可。

    如果物体不可分割就称为0/1背包问题,例如食物都是一份一份的,每一份都必须吃完。如果目前最贵的一份超过了你的饭量,那只好放弃,这样就不能用贪心法求解了。

      给定n种物品,背包i的重量是wi 、价值为vi ,背包的总容量为C。在装入背包的物品时对每种物品i只有两种选择,装还是不装也就是所谓的0/1。如何选择物品,使得装入背包的总价值最大呢?

    给定一个例子:有4个物品,其重量分别是2、3、6、5,价值分别为6、3、5、4,背包的容量为9.引入一个(n+1)x(C+1)的二维表dp[][],可以把每个dp[i][j]都看成一个背包,dp[i][j]表示把前i个物品装入容量为j的背包中获得的最大价值,i是纵坐标,j是横坐标。

    一:假设只装第一个物品。

      由于物品重量是2,所以背包容量小于2的都装不进去,得dp[1][0]=dp[1][1]=0;物品1的重量等于背包容量,可以装,价值为物品1的价值,dp[1][2]=6;容量大于2的背包,多于容量用不到,所以价值和容量2的背包一样。

    二:在一的基础上增加第二个物品。

      如果物品二的重量比背包容量大,那么不可能装物品2,从背包容量等于物品二开始:

      (1)如果装物品2(重量是3),那么相当于只把物品1装到容量减3的背包中。

      (2)如果不装物品2,那么相当于只把物品1装到背包中

      (3)取(1)和(2)的最大值,得dp[2][3]=max(3,6)=6。

    三:继续增加重复二,最后输出最大值即可。

    那如果要求输出0/1背包方案呢?这需要我们倒过来观察:

    dp[4][9]=max{dp[3][4]+4,dp[3][9]}=dp[3][9],说明没有装物品4,用x4=0表示;

    dp[3][9]=max{dp[2][3]+5,dp[2][9]}=dp[2][3]+5=11,说明装了物品3,用x3=1表示;

    dp[2][3]=max{dp[1][0]+3,dp[1][3]}=dp[1][3],说明没有装物品2,用x2=0表示;

    dp[1][3]=max{dp[0][1]+6,dp[0][3]}=dp[0][1]+6,说明装了物品1,用x1=1表示;

     练习:hdu2602:http://acm.hdu.edu.cn/showproblem.php?pid=2602

    代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int a[1010];
     4 int b[1010];
     5 int ans[1010];
     6 int main(int argc, char const *argv[])
     7 {
     8     int t;
     9     cin>>t;
    10     while(t--)
    11     {
    12         memset(a,0,sizeof(a));
    13         memset(b,0,sizeof(b));
    14         memset(ans,0,sizeof(ans));
    15         int n,m;
    16         cin>>n>>m;
    17         for (int i = 0; i < n; ++i)
    18         {
    19             cin>>a[i];
    20         }
    21         for (int i = 0; i < n; ++i)
    22         {
    23             cin>>b[i];
    24         }
    25         for (int i = 0; i < n; ++i)//遍历每个物品
    26         {
    27             for (int j = m; j >= b[i]; --j)//从每个物品的体积开始往后遍历
    28             {
    29                 ans[j]=max(a[i]+ans[j-b[i]],ans[j]);
    30                 //cout<<ans[j]<<" ";
    31             }
    32             //cout<<endl;
    33         }
    34         cout<<ans[m]<<endl;
    35     }
    36     return 0;
    37 }
    hdu2602
  • 相关阅读:
    继续OI
    [WARNING]考前必读?!
    近些日的总结吧
    续上文
    又是一年NOIP然鹅我考的是高数(虽然我没打并且内容与NOIP无关)(手动滑稽)
    轮船问题(DP基础)
    NOIP2016报零记
    字符数组
    HA-0302 退役
    各种模板(part 2)
  • 原文地址:https://www.cnblogs.com/125418a/p/12507991.html
Copyright © 2011-2022 走看看