NC145 01背包 动态规划 C++ 二维数组,一维数组 个人理解

动态转移方程使用二维数组

class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 计算01背包问题的结果
* @param V int整型 背包的体积
* @param n int整型 物品的个数
* @param vw int整型vector<vector<>> 第一维度为n,第二维度为2的二维数组,vw[i][0],vw[i][1]分别描述i+1个物品的vi,wi
* @return int整型
*/
int knapsack(int V, int n, vector<vector<int> >& vw) {
vector<vector<int>> W_M(n,vector<int>(V+1)); // 在不同的体积下,任意放不同的物品的组合所能取得的最大重量
/*初始化W_M的第一行和第一列*/
//初始化第一列, 第一列代表,在0体积下分别考虑放入任意 [0,i]之间的物品 最大重量是多少。很显然,没有体积为0的物品,所以这里的重量都是零
for(int i = 0;i < n ; i++){
W_M.at(i).at(0) = 0;
}
//初始化第一行,第一行代表,在[0-j]的体积下,考虑让第0个物品的放入,最大的重量是多少,如果能放就是第0个物品的重量,如果不能放下,那么重量就是0
for(int j = 0;j <= V;j++){
//如果第0个物品可以放下
if(vw.at(0).at(0) <= j) W_M.at(0).at(j) = vw.at(0).at(1);
else W_M.at(0).at(j) = 0;
}
for(int i = 1;i < n ; i++){ // 任意相同的物品组合在不同的体积下的最大重量
for(int j = 0;j <= V; j++){
//能考虑是否放入i物品的前提是,该物品的体积比j体积的背包要小
if(vw.at(i).at(0) <= j){
// j 体积下,放入i物品
/*如果在j 体积下放入第i个物品,那么j体积的剩余体积是j-vw.at(i).at(0),
很显然我们需要拿到在j-vw.at(i).at(0)体积下,不考虑第i个物品,只考虑第{0,i-1}个物品的最大重量*/
W_M.at(i).at(j) = W_M.at(i - 1).at(j - vw.at(i).at(0)) +vw.at(i).at(1);
// j 体积下,不放入i物品
/* 如果在j体积下,不放入i,物品,那么很显然是因为放入i物品后所占用的空间太大,重量太小,
那么就可能从[0,i-1]中选多一些体积小,重量大的物品放入,最后的在j体积下总重量会更大.
很显然这种情况要跟上面的情况对比一下,获得较大值,就能得出:
在j 体积下,放入任意的[0,i] 之间的物品所取得的的最大的重量。
*/
W_M.at(i).at(j) = max(W_M.at(i-1).at(j),W_M.at(i).at(j));
}else{
//如果当前i物品的体积比背包的体积j还要大,很显然,是不可能放入该物品的,所以
W_M.at(i).at(j) = W_M.at(i-1).at(j);
}

//很显然,不管是求W_M.at(i - 1).at(j - vw.at(i).at(0)),还是求W_M.at(i-1).at(j) ,都需要从已经求出来的数据中拿值
//W_M.at(i).at(j) 的值,要么来自于和它列相同,行小于一的前置数据;要么来自于行小于,列比它当前列小的数据。
//那么需要初始化W_M的第一行和第一列。

}
}
return W_M.at(n-1).at(V); // 返回的数据的意义是: 在体积V的限定下,考虑n个物品的放入情况的最大重量
}
};

 

 

动态转移方程使用一维数组,数组多次更新保存上一次计算的值

int knapsack(int V, int n, vector<vector<int> >& vw) {
vector<int> W_M(V+1); //在不同的V体积下,放不同的物品能取得最大重量
//初始化,考虑不同体积下,只考虑第一个物品的最大重量
for(int j = 0;j <= V;j++){
//如果第1个物品可以放下
if(vw.at(0).at(0) <= j) W_M.at(j) = vw.at(0).at(1);
else W_M.at(j) = 0;  // 如果第一个物品在这个体积下不能放下,那么这个最大重量为0
}

for(int i = 1; i < n;i++){   // 从第二个物品开始考虑,第一次考虑[0,1] 个物品任意放入的最大值,一直考虑到[0,n-1]个物品的任意放入的最大值,每一次这个循环走完,W_M 都是保存的在不同的体积下,任意考虑放入前i 个物品的最好重量, 这个循环走了n 次,那么W_M[0,....V] 也会更新n次。
for(int j = V;j >= 0; j--){    // 这里是不同体积下,针对同一讨论场景(从 0-i 个物品中任意放入)求不同的最好重量。
if(vw.at(i).at(0) <= j){      //i 物品的体积比 j 小于或者等于,才需要讨论这种情况
W_M[j] = max(W_M[j],W_M[j-vw.at(i).at(0)] + vw.at(i).at(1));     // 需要指出的是,不管j 取什么值,W_M[j] 一定是有值的,因为前面已经初始化了,并且 考虑的场景是从只考虑一个物品  到 考虑 n 个物品,考虑更多的物品计算出来的W_M[j] 会把前面的考虑的少的W_M[j] 覆盖掉。
}else{ // i 物品的体积比j体积大,就不需要讨论这种情况,甚至体积更小的j的就更不用讨论了。
break;
}
}
}
return W_M[V];
}

posted @ 2022-09-12 12:09  danieldai  阅读(43)  评论(0编辑  收藏  举报