在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],这个问题可以分解成两种情况来考虑:这是一个非黑即白的问题,因为一个物品只存在两种状态,放入背包
和没有放入背包
.
N1不放入背包,则问题转化为F[N-1][M]
,N1不放入背包,则物品数减一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 |
还有一个动态规划的详细解读博客动态规划扔鸡蛋!