01背包问题(小偷偷东西)—华为18年暑期优招机试题分析



  在8月18号参加了华为的优招机试,三道编程题,前两道难度不算很大,第一题很简单,第二题是经典的01背包问题,小偷偷东西,顺着这个机会也总结一下这个01背包问题,对于题目的描述一开始是凭记忆写的,后来在牛客网上看到了这个面试的题目,应该是对的,不过有小的区别也不影响题目的分析和编程实现。

考题说明

题目描述

  小偷来到了一个神秘的王宫,突然眼前一亮,发现5个宝贝,每个宝贝的价值都不一样,且重量也不一样,但是小偷的背包携带重量有限,所以他不得不在宝贝中做出选择,才能使偷到的财富最大,请你帮助小偷计算一下。

输入描述:

宝贝价值:6,3,5,4,6
宝贝重量:2,2,6,5,4
小偷背包容量:10

输出描述:

偷到宝贝的总价值:15

示例1

输入

6,3,5,4,6

2,2,6,5,4

10

输出

15

代码实现

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
    //之所以设置长度是六,我是为了和底下的6*11(第一行和第一列均为0)
    //的二维数组对应,第一个元素设置为0
    int value[6];//价值数组
    int weight[6];//重量数组

    int m;
    scanf("%d,%d,%d,%d,%d",&value[1],&value[2],&value[3],&value[4],&value[5]);
    scanf("%d,%d,%d,%d,%d",&weight[1],&weight[2],&weight[3],&weight[4],&weight[5]);
    cin>>m;

    //定义一个二维数组 dp[][],存放总价值
    int **dp;
    dp = new int*[6]; //定义了6行

    //这里是动态申请数组,每一行都是定值。其实也可以直接一开始就申请dp[6][11],然后memset(A,0,sizeof(A)),全部初始化为零;
    for(int i =0;i<=5;i++)
    {
        dp[i] = new int [m+1];//每一行都是在背包容量从0开始,到m,容量是m+1 
    }

    //初始化第一列为0
    for(int i =0;i<=5;i++)
    {
        dp[i][0] = 0;
    }
    //初始化第一行为0
    for(int j = 0;j<=m;j++)
    {
        dp[0][j] = 0;
    }

    //执行动态规划,自小到大计算,生成,value表
    for(int i = 1;i<=5;i++)
    {
        for(int j = 1;j<=m;j++)
        {
            if(j<weight[i])
            {
                //当背包的重量小于当前物品的重点时,则沿用上一行的value值
                dp[i][j] = dp[i-1][j];
            }
            else
            {
                //否则便进行计算,分两种情况,不包含i和包含i, 非一既零原则。
                //计算两种情况中较大的值,物品数从少到多进行计算
                //因为类似于斐波那契数列,前面会用到后面的值,故采用自底向上的计算方法
                //计算公式:F[i][j] = max(F[i-1][j],F[i-1][j-w[i]]+v[i])
                dp[i][j] = max(dp[i-1][j],dp[i-1][j - weight[i]]+value[i]);
            }
        }
    }
    cout<<dp[5][m]<<endl;
    return 0;

}

算法分析

  基本思路是将该问题转化为子问题进行求解。考虑N件物品在限重M的背包下可选择的最大价值F[N][M],这个问题可以分解成两种情况来考虑:这是一个非黑即白的问题,因为一个物品只存在两种状态,放入背包没有放入背包.

  1. N1不放入背包,则问题转化为F[N-1][M],N1不放入背包,则物品数减一
  2. N1放入背包,问题转化为value[N1]+f[N-1][M-weight[N1]],N1放入背包,则背包承重减少。

      原问题的解取上面两种情况中的最大值。既F[N][M] = max{F[N-1][M], (F[N-1][M-weight[N1]+value[N1]))}。接下来问题又变成了求解F[N-1][M]和 F[N-1][M-weight[N1]两个子问题。然后一直类推到一个物品时。以此类推的话我们解决原始问题需要子问题的解。我们需要先计算子问题,自底向上求解。解决顺序如下表。从左到右,从上到下计算。货品的顺序不影响最后的计算结果。

表格分析

  此表格是按照计算的方向来写的。计算的方法是一样的,分析方法也是一样,在此题中没有要求按序输出选中的物品,故输入顺序并没有影响。
  第一行和第一列初始化为0,则可以直接代入公式计算。
  
  第二行为只放入第一件物品,背包的最优值
  第三行为只放入前两件物品,背包的最优值
  …
  依次类推,最后的F[6][11]即为最优值。

货品 weight value 0 1 2 3 4 5 6 7 8 9 10
0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 2 6 0 0 6 6 6 6 6 6 6 6 6
2 2 3 0 0 6 6 9 9 9 9 9 9 9
3 6 5 0 0 6 6 9 9 9 9 11 11 14
4 5 4 0 0 6 6 9 9 9 10 10 13 14
5 4 6 0 0 6 6 9 9 12 12 15 15 15

猜你喜欢

转载自blog.csdn.net/qunqunstyle99/article/details/81836027