代码随想录算法训练营第三十三天| 01背包问题 二维 01背包问题 一维 416. 分割等和子集

01背包问题 二维

 要求:

有一个背包,他只能装4KG,分别有三个物品: 1 15;3 20; 4 30 ——》需要物品价值最大 

dp[i][j] 含义:

在放物品I 的时候在J背包容量下的物品最大值

递推公式: 

1,不放当前物品:dp[i-1][j]
2,放当前物品:(dp[i-1][j]) ->不应该是在当前容量下,i-1的最大价值,应该是:dp[i-1][j-weight[i]] 如果i 要3KG,那么就是i-1在1KG 下的最大值

初始化:

1,容量为0时,全为0,
2,物品0 对于J来说如果容量大于,那么就是value[0],否则为0

 测试代码:

// vector<int> weight = {1, 3, 4};
// vector<int> value = { 15, 20, 30 };
// int bagweight = 4;

代码:

 1 // 01背包问题
 2 // 要求:有一个背包,他只能装4KG,分别有三个物品: 1 15;3 20; 4 30 ——》需要物品价值最大
 3 // dp[i][j] 含义:在放物品I 的时候在J背包容量下的物品最大值
 4 // 
 5 // 递推公式: ——》疑问,如果放当前物品,但是其实不放,放下一个才是最大值,这是怎么实现的,也就是如何实现多个解,然后选择最大值?
 6 //    1,不放当前物品:dp[i-1][j]
 7 //    2,放当前物品:(dp[i-1][j]) ->不应该是在当前容量下,i-1的最大价值,应该是:dp[i-1][j-weight[i]] 如果i 要3KG,那么就是i-1在1KG 下的最大值
 8 // 
 9 // 初始化:
10 //    1,容量为0时,全为0,
11 //  2,物品0 对于J来说如果容量大于,那么就是value[0],否则为0
12 // 
13 // 测试代码:
14 //   vector<int> weight = {1, 3, 4};
15 //   vector<int> value = { 15, 20, 30 };
16 //     int bagweight = 4;
17 //
18 int test_2_wei_bag_problem1(vector<int>& weight, vector<int> &value, int& bagweight)
19 {
20     vector<vector<int>> dp(weight.size(), vector<int>(bagweight+1, 0));
21 
22     for (int i = 0; i <= bagweight; i++)
23     {
24         if (weight[0] <= i)
25         {
26             dp[0][i] = value[0];
27         }
28     }
29 
30     for (int i = 1; i < dp.size(); i++)
31     {
32         for (int j = 0; i <= bagweight; j++)
33         {
34             if (bagweight < weight[i])
35             {
36                 dp[i][j] = dp[i - 1][j];
37                 continue;
38             }
39 
40             int cur1 = dp[i - 1][j];
41             int cur2 = value[i] + dp[i - 1][j - weight[i]];
42 
43             dp[i][j] = max(cur1, cur2);
44         }
45     }
46 
47     int result = INT_MIN;
48     for (int i = 0; i < dp.size(); i++)
49     {
50         if (result < dp[i][bagweight])
51         {
52             result = dp[i][bagweight];
53         }
54     }
55 
56     return result;
57 }
 

 01背包问题 一维 

dp[J]:

当容量为 J 的时候的最大值

递推公式:

// J : 当前容量 I:当前物品
// 1,不放当前物品:dp[J] = dp[J]
// 2,放当前物品: dp[J] = dp[J - weight[I]] + value[I] 

初始化:

// 1,dp[o] = 0

遍历顺序:

// 设想当容量为1的时候放了一个A,容量为2的时候再放了物品A dp[1] = 20 dp[2] = dp[1]+20 = 40
// 如果dp[i][j]
// dp[A][1] ; dp[B][2] = dp[A][1]+B 而不是加A
// 理想的情况:dp[1] 放了物品A,那么dp[2] 的时候就不要再放物品A了
// 因为每次是针对单个容量来搞的,并不代表和dp[0]有任何联动?——》不正确
// 先看物品A, 然后让容量从高到底来做,——》这样和dp[i-1] 有关系么? ——》 有关系,可以看下面
// 可以保证A在每个容量里只放了依次
// 当下一个容量的时候,就可以用上一个物品了

代码 

 1 // 使用一个一维数组 来搞动态规划
 2 // dp[J]:当容量为 J 的时候的最大值
 3 // 递推公式:
 4 //  J : 当前容量 I:当前物品
 5 //    1,不放当前物品:dp[J] = dp[J]
 6 //    2,放当前物品: dp[J] = dp[J - weight[I]] + value[I]
 7 // 
 8 // 初始化:
 9 //    1,dp[o] = 0
10 // 遍历顺序:
11 // 设想当容量为1的时候放了一个A,容量为2的时候再放了物品A dp[1] = 20  dp[2] = dp[1]+20 = 40
12 // 如果dp[i][j]
13 //    dp[A][1] ; dp[B][2] = dp[A][1]+B 而不是加A
14 // 
15 // 理想的情况:dp[1] 放了物品A,那么dp[2] 的时候就不要再放物品A了
16 // 因为每次是针对单个容量来搞的,并不代表和dp[0]有任何联动?——》不正确
17 // 先看物品A, 然后让容量从高到底来做,——》这样和dp[i-1] 有关系么? ——》 有关系,可以看下面
18 //    可以保证A在每个容量里只放了依次
19 // 当下一个容量的时候,就可以用上一个物品了
20 //
21 int test_1_wei_bag_problem(vector<int>& weight, vector<int>& value, int& bagweight) 
22 {
23     vector<int> dp(bagweight + 1, 0);
24 
25     for (int i = 0; i < weight.size(); i++)
26     {
27         for (int j = bagweight; j >= 0; j--)
28         {
29             if (j < weight[i])
30             {
31                 continue;
32             }
33             else 
34             {
35                 dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
36             }        
37         }
38     }
39 
40     return dp[bagweight];
41 }

 

 

 416. 分割等和子集  

 

要求:

输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。
难点:

难点:

1,容量是什么

2,怎么保证当前选择的,下一个不在选择

思路:

只要里面的元素可以满足 sum(nums)/2 就可以分成这样的子集

而不需要,背包是两个子集,然后这个放一个,其他的放,那么它的weight怎么弄?是想不通的

细节:

物品是 nums

容量是 sum(nums)/2  {和weight 的定义相等,就是让容量可以满足,然后是最大值}

weight value都是nums,

所以比较的函数,仍然是 max,存放的是可以满足这个情况的最大值

代码:

 1 //注意:背包问题的目标是:让容量里面的价值达到最大
 2 // 1,背包的容量需要最大化
 3 // 2,里面的价值需要最大化
 4 // 
 5 // 要求:只包含正整数,非空,分割成两个子集,使得这两个子集和相等
 6 // 思路:思考背包问题能不能行
 7 // 有N个物品,两个容量,要求这两个容量的和相等
 8 // 容量: 1-(N-1)放进去
 9 // 
10 // 难点: 怎么做到这个容量 和下一个容量之间的 物品不一致?
11 // 
12 // 数组dp[i][j] 当把当前数字I放到第J个背包中,它的和最大?
13 // 
14 // 修正后的思路 : 只要有 n 个物品的和可以填满 sum(nums)/2 就可以满足要求
15 // N个物品,容量:n个物品的和,可以填满,容量是sum(nums)/2
16 // 
17 // dp[n]:第N 个容量的时候 它的最大值
18 // 递推公式:
19 //    1,不放当前物品:dp[n] = dp[n]
20 //    2,放当前物品:dp[n] = value[i] + dp[n-weight[i]]
21 // 
22 // 其中value weight 都为nums
23 //
24 bool canPartition(vector<int>& nums) 
25 {
26     int sum_ = 0;
27     for (int num : nums)
28     {
29         sum_ += num;
30     }
31 
32     if (sum_ % 2 == 1)
33     {
34         return false;    
35     }
36     vector<int> dp((sum_ / 2)+1, 0);;
37 
38     for (int i = 0; i < nums.size(); i++)
39     {
40         for (int j = (sum_ / 2); j >= nums[i]; j--)
41         {
42             dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
43         }
44     }
45 
46     return dp[(sum_ / 2)] == (sum_/2);
47 }

 

 

posted @ 2023-07-18 15:30  博二爷  阅读(3)  评论(0编辑  收藏  举报