通俗易懂的 01背包问题

问题描述

有一个W容量的背包.和 I个物品,其中每个物品重 weight[i] 每个物品的价值为value[i]
问在不超过背包容量的情况下,怎么装入物品,可以使背包内的物品价值达到最大,其中对于每个物品,
只能选择放或者不放

问题分析

乍一看无从下手,但是认真分析以下就可以得出 :
假设在放入 i - 1个物品后,背包里物品重量是total_weight,价值是total_value,在此刻背包的选择是最佳的;
对于物品 i 是否放入背包呢? 这里我们考虑:
1.我们是否可以将背包里的一些物品拿出来,腾出i的重量weight[i],放入i后再看此刻背包中的总价值total_value,是否大于不放物品i时背包的总重量的total_value,
一句话总结就是,牺牲背包内 weight[i]的空间,来换取物品value[i] 的价值, 看是否值得这么干. 当然万一当前背包牺牲的空间是空闲空间(没有将其他物品换出),那么肯定要把i物品加入.但更通用的思想就是加粗的那句话,个人在理解背包问题的解法时,就是这一点过了好久才想通,感觉和正常思维不太一样…
2 最后要考虑的是,如果此刻背包重量total_weight 如果小于物品i的重量weight[i], 上述牺牲空间换价值的策略肯定行不通, (背包内腾不出物品i的空间)那么对于此刻的背包采取的策略就是不放 i 物品,

那么我们思考一下,如果需要求 6kg的背包最优解,只要我知道了0 1 2 3 4 5 kg下背包的最优解

然后在5kg的情况下采取以上策略就能的出6kg的最优解(存在递推关系)

在0kg下 肯定total_value = 0 因为放不下任何物品
在0物品情况下,total_value = 0 因为没有物品

总结一下公式

这里写图片描述
其中 v就是当前背包的总价值 i是当前物品的编号 j就是当前背包的总容量, Wi是物品I的重量

附上代码

#include<stdio.h>
#define item_number 3
#define packge_weight 5
#define Max(a,b) (a > (b) ? a : ( b ))
int value[] = { 0,7, 9, 1 };
int weight[] = { 0,3, 2, 1 };
//要存入0重量 0物品的状态 所以数组 + 1
int total_value[item_number + 1][packge_weight + 1] = {0};
int main()
{
    int i,j;
    for(i = 0; i <= item_number; i++) {
        for( j = 0; j <= packge_weight; j++)
        {
            //背包承重为空或者没有物品
            if (i == 0 || j == 0 )
            {
                total_value[i][j] = 0;
                continue;
            }
            //第i件物品大于 当前的总重量
            //肯定换不了
            if( weight[i] > j )
                total_value[i][j] = total_value[i - 1][j];
            //
            else
            {
                  //选择策略
                total_value[i][j] = Max(total_value[i - 1][j], total_value[i - 1][j - weight[i]] + value[i]);
            }
        }
    }
    //打印背包从0kg到packge_weight的状态
    for(i = 0; i <= item_number; i++) {
        for( j = 0; j <= packge_weight; j++)
        {
            printf("%2d ",total_value[i][j]);
        }
        printf("\n");
    }
        printf("\n");
        //最优解
    /*printf("%d \n", total_value[item_number][packge_weight]);*/
}

总结

其实这就是一个动态规划的过程.. 感觉名字很高大上

对于这类问题, 我们可以总结到
1. 可以从i - 1 的最优解得出 i状态的最优解
2. 从i - 1的状态到i的状态 可能存在不同的方法,需要我们去从中选出最优的方法,本问题就是要在选和不选中抉择
3. 对于选择和不选择,我们必须用数据说话,所以要把每个状态所有可能用到的数据以填表的形式记录下来 以便后续状态计算时用到

猜你喜欢

转载自blog.csdn.net/kwinway/article/details/80075808