0/1背包问题总结

2024-07-19 1202阅读

文章目录

  • 🍇什么是0/1背包问题?
  • 🍈例题
    • 🍉1.分割等和子集
    • 🍉2.目标和
    • 🍉3.最后一块石头的重量Ⅱ
    • 🍊总结

      0/1背包问题总结

      博客主页:lyyyyrics

      🍇什么是0/1背包问题?

      0/1背包问题是一个经典的组合优化问题,其描述如下:

      假设有一个背包,它能够承载一定的重量。现在有一组物品,每个物品有各自的重量和价值。我们的目标是在不超过背包承载重量的前提下,选择一些物品放入背包中,使得背包中物品的总价值最大化。

      具体来说,假设有 n n n个物品,其重量分别为 w 1 , w 2 , . . . , w n w_1, w_2, ..., w_n w1​,w2​,...,wn​,对应的价值分别为 v 1 , v 2 , . . . , v n v_1, v_2, ..., v_n v1​,v2​,...,vn​。背包的承载重量为 W W W。我们需要在这 n n n个物品中选择一些放入背包中,使得这些物品的总重量不超过 W W W,且总价值最大化。

      数学公式可以表示为:

      Maximize ∑ i = 1 n v i x i subject to ∑ i = 1 n w i x i ≤ W x i ∈ { 0 , 1 } , i = 1 , 2 , . . . , n \begin{align*} \text{Maximize} \quad & \sum_{i=1}^{n} v_ix_i \\ \text{subject to} \quad & \sum_{i=1}^{n} w_ix_i \leq W \\ & x_i \in \{0, 1\}, \quad i=1,2,...,n \end{align*} Maximizesubject to​i=1∑n​vi​xi​i=1∑n​wi​xi​≤Wxi​∈{0,1},i=1,2,...,n​

      其中, x i x_i xi​表示第 i i i个物品是否放入背包中。若 x i = 1 x_i=1 xi​=1,表示放入;若 x i = 0 x_i=0 xi​=0,表示不放入。

      🍈例题

      🍉1.分割等和子集

      题目:

      0/1背包问题总结

      样例输出和输入:

      0/1背包问题总结

      根据描述,这道题就是让我们求一个数组是否能将其分成两块 ,然后这两块是相等的,如果能返回true,如果不能则返回false。

      算法原理:

      首先我们注意到,这道题要将数组分成两个部分,这两个部分是否相等,我们可以转化为分成一个部分,这个部分是数组总和的一半?很显然是可以的,这样转换之后其实就已经是背包问题了,这个数组中的数就是物品,数组中的数就代表每个物品的价值,然后数组中的数的总和的一半就是这个背包的容量,问题就 转化为,我们是否可以从数组中挑出一些物品,使得物品的体积恰好能把这个 背包塞满?

      状态表示:dp[i][j]表示前i个数中的所有的选法中,是否存在和为j的选法,如果存在则是true,如果不存在则就是false。

      状态转移方程:状态转移方程还是考虑i位置和j位置。

      0/1背包问题总结

      如果能选的话,应该是选和不选中有一个满足就够了,所以这里应该还要取一个||,dp[i][j]=dp[i-1][j]||dp[i-1][j-nums[i]]

      初始化:0/1背包问题总结

      首先看第一行,从1开始,从0个数中选,和为1的,这种情况是不存在的,所以应该是false,后面的从0个数中选的都是false,,我们来看第一列,从0个数中选和为0,那就是不选,所以为true,从1个数中选和为0,可以不选,也是true,所以我们只需要 初始化第一列,初始化为true。

      代码:

      class Solution {
      public:
          bool canPartition(vector& nums)
          {
              int n = nums.size();
              int sum = 0;
              //求和
              for (auto e : nums)sum += e;
              //如果和是奇数的话直接返回
              if (sum % 2 == 1)return false;
              //先定义一个aim表示和的一半
              int  aim = sum / 2;
              //创建dp表
              vector dp(n + 1, vector(aim + 1));
              //初始化dp表的第一列为true,因为如果和为零的话是有可能的。
              //如果什么都不选的话,当前和就是0
              for (int i = 0;i 
                  dp[i][0] = true;
              }
              for (int i = 1;i 
                  for (int j = 1;j 
                      //不选的话就是前一个状态的bool值
                      dp[i][j] = dp[i - 1][j];
                      //如果能选的话,只要有一种满足就表示满足
                      if (j = nums[i - 1])dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i - 1]];
                  }
              }
              //返回和为aim的状态
              return dp[n][aim];
          }
      };
      
      public:
          int findTargetSumWays(vector
              int n = nums.size();
              int sum = 0;
              for (auto e : nums)sum += e;
              int aim = (sum + target) / 2;
              if (aim 
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]