回到原点 重新感受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 }