回到原点 重新感受01背包的魅力 ZerOnePack

  01背包问题是很经典的动态规划问题,给定总容量T,物品的件数。然后给定数组weight[k] value[k]来求解背包装上物品所带来的最大收益。

  最开始的时候是设置二维DP数组来求解问题 我们不妨设数组DP[i][j]来表示的是前i件物品在容量为j的情况下所取得的最大收益值,当我们设置好一个DP数组的时候,在思考状态转移方程的时候,可以假设前一状态的方程已经得到了解决,这样的话我们可以很方便的得到01背包的状态转移方程。

  dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]] + value[i]);

  进一步的时候,我们可以考虑空间优化的问题 也就是ACM选手所说的利用滚动数组来实现空间优化,我们很容易发现,在考虑状态转移方程的时候,我们只考虑相邻的层次之间的状态转移。那么我们可以考虑来用一维的数组来代替二维数组,但要改变内层的循环顺序,来考虑覆盖的前后次序。

  另一方面,我们可以考虑初始化的问题。即初始情况下下的dp数组的每个元素的值,在考虑初始化情况下,我们有两种方法,第一种是考虑第一维的情况,即在脑海里模拟一下,我们可以相想到是dp[i]=0的情况,另一方面,背包问题还有个有趣的设置是必须要求背包装满的情况,在一般的情况下,我们或许没有严格要求背包装满,比如当一个容量背包为100,而第一件物品的重量只有10的时候,我们会发现常规方法是使的10-99所有的值都设置为第一件物品的值。所以我们可以在初始化的条件下,设置dp[0]=0,而其他的dp[i]=-INF;来保证最后求得的值是背包装满的值。这样的话 如果dp【i】<0说明无法装满背包。

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <string.h>
 4 #include <cmath>
 5 using namespace std;
 6 const int Maxlen = 1e5;
 7 int main(){
 8     
 9     //实现01背包 问题 ZerOnePack
10     int t,k,i,j,x;
11     int value[Maxlen],weight[Maxlen],dp[Maxlen];
12     //dp[i][j]本质上是前i件物品在容量为j的时候的最大值
13     //最后用一维数组来实现本质上还是利用了滚动优化 数组内存的思想
14     while(~scanf("%d %d",&t,&k)){
15         for(i=1;i<=k;i++)
16             scanf("%d %d",&value[i],&weight[i]);
17             memset(dp,0,sizeof(dp));
18         for(i=1;i<=k;i++){
19 
20             for(j=t;j>=weight[i];j--){
21                 dp[j]=max(dp[j],dp[j-weight[i]] + value[i]);
22             }
23 //            for(x=1;x<=t;x++)
24 //                printf("%d ",dp[x]);
25 //            printf("\n");
26         }
27         printf("%d\n",dp[t]);
28     }
29     
30     
31     
32     return 0;
33 }

猜你喜欢

转载自www.cnblogs.com/visper/p/10065628.html