学习交流加

  • 个人qq:
    1126137994
  • 个人微信:
    liu1126137994
  • 学习交流资源分享qq群:
    962535112

一个背包有一定的承重cap,有N件物品,每件都有自己的价值,记录在数组v中,也都有自己的重量,记录在数组w中,每件物品只能选择要装入背包还是不装入背包,要求在不超过背包承重的前提下,选出物品的总价值最大。

给定物品的重量w价值v及物品数n和承重cap。请返回最大总价值。

测试样例:
[1,2,3],[1,2,3],3,6
返回:6

这个背包问题,还是很不好理解的其实!

解题思路:
假设物品编号为1~n,一件一件考虑是否装入背包内。有两个变量w(代表各个物品的重量数组)和v(代表各个物品的价值数组)。同样还是开辟一个新的空间,大小为dp[n][cap],那么,dp[i][j]代表前i件物品,且背包承重为j时的物品最大价值!!那么dp[n][cap]就是我们的最终所求,即矩阵的最右下角!!!

求解步骤:
1、求第一行:
dp[0][j]代表前0件物品的价值,都为0,所以dp[0][j]=0
2、求第一列:
dp[j][0]代表前j件物品,但是背包的承重为0,所以总价值也是都为0,所以dp[i][0]=0
3、求其他行:
dp[i][j]代表前i件物品,背包的承重为j时,所能获得的最大价值。可以分为以下两种情况:
一:拿第i件物品
拿第i件物品的时候,首先要保证(条件判断)第i件物品的重量w[i-1](注意这里为什么是i-1,因为数组w是从0号开始,它的0号对应的是矩阵第一列的1号,当矩阵的为i时,对应的w里应该是i-1)不能超过j(超过j就不会拿第i件产品了)。而当我们拿了第i件物品后,前i-1件的物品获得的最大价值也会重新分布(有可能会减少),此时到底是拿第i件物品后价值大还是不拿第i件物品产品大呢?这个是不确定的,所以需要去判断选择.
1)拿的话,价值应该等于 v[i-1](第i件物品的价值,为什么是i-1原因与w[i-1]一样)加上前i-1件物品,背包承重j-w[i-1]的价值
2)不拿的话,价值就直接等于dp[i-1][j]
然后选择上述的较大值就行
此时:

if(j>w[i-1])
	dp[i][j] = max(dp[i-1][j],v[i-1]+dp[i-1][j-w[i-1]])

二:不拿第i件物品
当我想拿第i件物品时,如果w[i-1]>j,就不能拿,因为一拿就超过背包的承重。所以此时的价值就直接等于前i-1件物品,背包承重i时的价值!
即:

if(j<w[i-1])
	dp[i][j] = dp[i-1][j];

最终的代码如下:
运行通过了所有的测试用例!

class Backpack {
public:
    int maxValue(vector<int> w, vector<int> v, int n, int cap) {
        // write code here
        int dp[n+1][cap+1];
        //初始化一列
        for(int i=0;i<n+1;i++)
            dp[i][0]=0;
        //初始化第一行
        for(int j=0;j<cap+1;j++)
            dp[0][j]=0;
        //求其他行的值 
        for(int i=1;i<n+1;i++)
        {
            for(int j=1;j<cap+1;j++)
            {
                //拿第i件物品,拿了后的总价值不一定比不拿前的总价值高(因为拿了第i件物品后,前面的i-1件物品的分配汇会改变)
                if((j-w[i-1])>=0)
                    dp[i][j]=max(v[i-1]+dp[i-1][j-w[i-1]],dp[i-1][j]);
                //不拿第i件物品
                else
                    dp[i][j]=dp[i-1][j];            }
        }
        return dp[n][cap];
    }
};