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

 

posted @ 2020-03-16 23:41  DemonSlayer  阅读(510)  评论(0编辑  收藏  举报