两种背包问题的学习记录

##有关01背包

#采药

       一开始就如同大多数的蒟蒻一样,本人也只会一点点dp,于是就想到了用递归,

因为只用考虑到一层的情况,毕竟方便理解,很容易就得出了一下的方程

 

dp[x][y]=max(dps(x+1,y+c[x])+v[x],dps(x+1,y));

 

       用x表示个数,用y来表示容量,一次只考虑当前这种放不放,超方便又好理解;

#一维压缩

    在上面情况里用了二维数组,但其实可以压缩到一维,对于当前的种类可以省略,

当时看题解的时候用了各种状态转移方程的推导,头都炸了,直到GWX巨佬指点,

      对于基础的背包,我们在第i个物品的时候可以这样想,一个背包能放下这个物品,

那么就比较它和不放时候的大小,这里我用了for循环,方便一会与无限背包做比较;

1  for(i=1;i<=M;i++){
2         for(j=T;j>=t[i];j--)
3             f[j]=max(f[j],f[j-t[i]]+p[i]);
4 }

 

      这里面i表示了物品,而j就表示在背包容量为j时的背包,于是这段程序的意思就是在i物品时遍历背包的情况;

在j容量的情况下,f[j-t[i]]+p[i]其实就是表示你在j-t[i]容量的背包里放了一个i物品。这就很动归。

    需要注意的是j一定是从右往左计算的,这个就是他和无限背包的最大区别,下面会说。

##有关无限背包

#疯狂的采药

        这种背包区别于普通的背包在于它的一个物品可以无限装,本身与上面上面的没什么区别,

用二维数组的话只要多引入一个变量表示物品就好,直接扒一段代码:

 

1     for(i=1;i<=M;i++)
2     {
3         for(j=0;j<t[i];j++)
4             f[i][j]=f[i-1][j];
5         for(j=t[i];j<=T;j++)
6             f[i][j]=max(f[i-1][j],f[i][j-t[i]]+p[i]);
7     }

 

 #一维压缩

    这里才是我真正遇到的问题,话不多说先上一段代码:

 

1  for(i=1;i<=M;i++){
2         for(j=t[i];j<=T;j++)
3             f[j]=max(f[j],f[j-t[i]]+p[i]);
4 }

 

  可以看见的是,这段代码与普通的背包几乎一样,只不过是运行背包的顺序反了一下,

就是这里让我想了一会,神犇们的题解一上来就是状态转移方程的各种变形,看的我头都掉了,

多亏了大佬的指点。

  抽象的理解一下,在普通背包的代码

 

1   for(i=1;i<=M;i++){
2          for(j=T;j>=t[i];j--)
3              f[j]=max(f[j],f[j-t[i]]+p[i]);
4  }

 

 

   里面,递推的顺序是从容量大的背包情况下开始的,也就是说,在遍历到容量为j的背包时,

会选择在j-t[i]也就是上一个背包中放不放,最后只改变了当前情况下的背包,在这一种物品时,

j背包的情况只可能从上一个物品运算完后的背包到达,而当前的背包在这个物品中不可能再被选到

所以一个物品最多放进一次;

  而在完全背包的代码

 

1  for(i=1;i<=M;i++)
2         for(j=t[i];j<=T;j++)
3             f[j]=max(f[j],f[j-t[i]]+p[i]);

 

 

里,顺序是从容量小的背包开始考虑的,也就是说,在考虑到j背包时,判断跟普通的背包一样,

都是放或不放的问题,但在容量小的背包做完后,在之后容量大的背包里还可能再次选到小容量的背包

这就使的在同一个物品被放入当前背包后,之后的大背包在考虑到这个背包时,这个背包里就已经有过这个物品了;

这就是无限的放入一个物品了。

真是好神奇的动态规划。

不会状态转移方程式运算的我蒟蒻还是更偏向想象问题的模型啊,感谢GWX大师的帮助。

posted @ 2020-05-14 18:01  Can'you星痕  阅读(144)  评论(0编辑  收藏  举报