andre_joy

导航

小结论(3)

分组背包的学习结束了,收获颇多,分组背包是个很神奇的东西。

分组背包经常一般是三种情况。

(1)每组物品最多选一个(最常规的)

for(i = 0; i < n; i++) //n是总共种类
    for(j = vmax; j >= 0; j--) //vmax是背包最大容量
        for(k = 0; k < num[i]; k++) //num[]为该类物品个数 
            if(j >= v[k]) dp[j] = max(dp[j], dp[j-v[k]+w[k]]);

这是一维的情况,二维很容易扩展,接下来两种题目必须用二维。而且用到用到01背包里面恰好到达的概念,必须通过之前已经得到的状态才能转到现在的状态。

(2)每组物品随便选

memset(dp, -1, sizeof(dp));
dp[0][0] = 0;
for(i = 1; i <= n; i++) //n是总共种类
    for(k = 0; k < num[i]; k++) //num[]为该类物品个数 
    {
        for(j = vmax; j >= v[k]; j--) //vmax是背包最大容量
        {
            if(dp[i][j-v[k]] != -1) dp[i][j] = max(dp[i][j], dp[i][j-v[k]]+w[k]);
            if(dp[i-1][j-v[k]] != -1) dp[i][j] = max(dp[i][j], dp[i][j-v[k]]+w[k]);
        }
        for(j = 0; j <= vmax; j++)
            dp[i][j] = max(dp[i][j], dp[i-1][j]);
    }

(3)每组物品至少选一个

memset(dp, -1, sizeof(dp));
dp[0][0] = 0;
for(i = 1; i <= n; i++) //n是总共种类
    for(k = 0; k < num[i]; k++) //num[]为该类物品个数 
    {
        for(j = vmax; j >= v[k]; j--) //vmax是背包最大容量
        {
            if(dp[i][j-v[k]] != -1) dp[i][j] = max(dp[i][j], dp[i][j-v[k]]+w[k]);
            if(dp[i-1][j-v[k]] != -1) dp[i][j] = max(dp[i][j], dp[i][j-v[k]]+w[k]);
        }
    }

(3)的代码与(2)的代码区别只在于少了两行,这是因为(3)必须是有之前得到的状态转移过来,而(2)可以继承之前得到的状态。

注意!!!这里面的一个细节。转换的时候是先判断的同类的物品,再判断之前类物品!!!这是因为如果一个物品v值是0,那么如果你先判断之前类物品,在j为0时肯定会转移一次,那么你再判断同类物品,在j为0时又会转移一次。而如果你先判断同类物品,因为初始化是-1,所以不会转移。

posted on 2012-10-02 01:52  andre_joy  阅读(150)  评论(0编辑  收藏  举报