0-1背包问题和完全背包问题

2023-10-30

先总体介绍一下0-1背包和完全背包的区别

主要是01背包和完全背包(背包九讲里面的其他背包问题,都是竞赛级别的,leetcode上面没有)

01背包就是:背包存在一个最大容量V,每个物品有两个参数:体积w和价值v,目的是在不超过背包最大容量的前提下,取出物品的价值最大

如果每个物品的数量只有1个,那就是01背包问题

如果每个物品的数量是无限的,那就是完全背包问题

leetcode上没有纯01背包的问题,都是01背包应用方面的题目,也就是需要转化为01背包问题。

动态规划要搞清楚三个问题:

(1)dp[i][j]的含义

(2)状态转移方程 

(3) dp数组开多大,最后返回什么,一般是返回数组的最后一个元素

物体的数量是m(m个物体),背包可以装的最大容量为w,开一个dp[m+1][w+1]的二维数组

第i件商品的重量为weight[i-1],重量为values[i-1]

状态转移方程就是考虑第i个物品放不放的进去  

 dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i-1]] + value[i-1]);
 前者是不拿第i个物品,后者是拿第i个物品(拿前i-1个物品的价值+第i个物品的价值就是拿前i个物品的价值,这里要主要第i个物品的重量是weight[i-1],价值是value[i-1])

代码实现:

传入三个参数,weight数组,value数组,bagweight(背包能装的最大重量)

物品有weight[]数组和values[]数组

背包的能装的最大重量为bageweight

public int  help(int[] weight,int[] value,int bagweight)
{
   int[][]  dp=new int[weight.length+1][bagweight+1];

  
   // weight数组的大小 就是物品个数
   for(int i = 1; i < weight.length+1; i++) // 遍历物品
   { 
       for(int j = 1; j < bagweight+1; j++) // 遍历背包容量
       {
           if (weight[i-1]>j) //如果光是第i个物品本身的重量已经超过了背包容量,这说明肯定不能取第i个物品,第i个物品对应的是weight[i-1]和value[j-1]
           {
               dp[i][j] = dp[i - 1][j]; 
           }
           else 
           {
             dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i-1]] + value[i-1]);
             //前者是不拿第i个物品,后者是拿第i个物品(拿前i-1个物品的价值+第i个物品的价值就是拿前i个物品的价值,这里要主要第i个物品的重量是weight[i-1],价值是value[i-1])
           }
        }
    }
    return   dp[weight.length][bagweight];
}

这两个问题都是横轴是可以选的数,纵轴是要拼成的target

不要想压缩到一维数组,掌握二维数组的解法就够了

这两种背包问题就是二维dp问题,把二维表格画出来基本就能解决了

力扣416  分割等和子集

这个问题就转化成,问你这个集合的子集中,是否存在一个子集,它的所有元素之和等于target

其中 dp[i] 表示是否可以找到一个子集,使得其元素和等于 i

step1:开二维dp数组:int[][] dp=new int[nums.length][],确定dp[i][j]的含义

 step2:第一行,只用nums[i]这一个数,肯定只能拼出nums[i],所以:

for(int j=0;j<=target;j++)
{
  if(j==nums[0])
  { 
     dp[0][j]=true;
  }
}


step3:状态转移方程

dp[i][j]表示从nums[0]-nums[i]中这些数中能否拼成j

(1)当nums[i]=j时,表示nums[i]一个数就可以拼出j,所以dp[i][j]一定是true

(2)如果nums[i]<j,表示nums[i]这个数小于j,那么dp[i][j]=dp[i-1][j-nums[i]],也就是说前面的数能拼成j-nums[j],那么加上nums[i]这个数,就能拼成j

(3)如果dp[i-1][j]=true,表示不用nums[i]这个数,也能拼出j,那么说明dp[i][j]一定是true

完整代码如下:

class Solution
{
    public boolean canPartition(int[] nums) 
    {
       if(nums.length==0)  return false;
       int  n=nums.length;
       int sum=0;
       for(int num:nums)
       {
           sum=sum+num;
       }
    
       //总和为奇数,那肯定是不能分成两个和相等的子集
       if(sum%2!=0)  return false;

       int target=sum/2;

       boolean[][] dp=new boolean[nums.length][target+1];

       for(int j=0;j<=target;j++)
       {
           if(j==nums[0])
           { 
              dp[0][j]=true;
           }
       }

       //从第一行开始,然后是第二行,第三行.....
       for(int i=1;i<nums.length;i++)
       {
           for(int j=0;j<=target;j++)
           {
               if(nums[i]==j)  dp[i][j]=true;
               if(nums[i]<j)  dp[i][j]=dp[i-1][j-nums[i]]||dp[i-1][j];
               if(nums[i>j])   dp[i][j]=dp[i-1][j];
           }
       }
       return  dp[nums.length-1][target];  
    }
}

完全背包问题:

public class Knapsack {
    public static int knapsack(int[] w, int[] v, int V) {
        int n = w.length;
        int[][] dp = new int[n + 1][V + 1];
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= V; j++) {
                for (int k = 0; k * w[i - 1] <= j; k++)//此时背包容量大小为j
                {
                    dp[i][j] = Math.max(dp[i-1][j], dp[i - 1][j - k * w[i - 1]] + k * v[i - 1]);
//前者是不加入第i件物品,后者是加入第i件物品(第i件物品的重量是weight[i-1],价值是value[i-1])
                }
            }
        }
        return dp[n][V];
    }
}

力扣322 零钱兑换(每种硬币的数量是无限的)

定义 dp[i][j]为考虑前 i件物品,凑成总和为 j 所需要的最少硬币数量

class Solution 
{
    public int coinChange(int[] coins, int amount) 
    {
        int n=coins.length,m=amount;
        int INF=Integer.MAX_VALUE;
        int[][]dp=new int[n+1][m+1];
        //初始化,amount=0
        for (int i = 1; i <= n ; i++)
        {
            dp[i][0]=0;
        }
        //初始化,coins=0
        for (int i = 1; i <= amount; i++)
        {
            dp[0][i]=INF;
        }
        for (int i = 1; i <=n ; i++)
        {
            for (int j = 1; j <=m ; j++) 
            {
                dp[i][j]=dp[i-1][j];
                for (int k = 1; k*coins[i-1]<=j ; k++)
                {
                      if(dp[i-1][j-k*coins[i-1]]!=INF)
                      {
                          dp[i][j]=Math.min(dp[i-1][j-k*coins[i-1]]+k,dp[i][j]);
                      }
                }
            }
        }
        return dp[n][m]==INF?-1:dp[n][m];
    }
}
class Solution {
    static int N = 0x3f3f3f3f;
    public int coinChange(int[] coins, int amount) {
        int n = coins.length;
        int[][] f = new int[n + 1][amount + 1];
        for(int i = 0; i < n + 1; i ++){
            Arrays.fill(f[i], N);
        }
        for(int i = 0; i < n + 1; i ++) f[i][0] = 0;
        for(int i = 1; i <= n; i ++){
            for(int j = 0; j <= amount; j ++){
                int maxCount = j / coins[i - 1];
                for(int k = 0; k <= maxCount; k ++){
                    f[i][j] = Math.min(f[i][j], f[i - 1][j - coins[i - 1] * k] + k);
                }
            }
        }
        if(f[n][amount] == N) return -1;
        else return f[n][amount];
    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

0-1背包问题和完全背包问题 的相关文章

  • 吉比特无源光纤接入用户端设备_网管型光纤收发器产品功能及技术特点详解

    网管型光纤收发器采用主从式管理结构 支持SNMP及Web图形化和Telnet命令行方式带外网管 为电信运营商的维护 管理提供了便捷 可靠的手段 接下来就由飞畅科技小编来为大家介绍下网管收发器的功能及技术特点 一起来看看吧 网管收发器的功能介
  • ubuntu 安装openjdk

    在安装环境的过程中可能需要切换安装版本 安装openjdk sudo apt update sudo apt install openjdk 8 jdk sudo apt install openjdk 11 jdk 切换版本 sudo u
  • linux检查是否有D进程,Linux的CPU-Load虚高之进程的D状态

    写在前面 前几天从同事手里接盘了一个 HHKB 的键盘 虽说是顶级的配置 但是如果不提一句的话估计大家都不会意识到码出这篇博文的工具如此高大上 同时意味着我要持续吃土小半年了 就像之前博文提到的 我工作的重心从业务开发逐渐向基础平台建设转移

随机推荐

  • 模拟cisp-pte 综合题三个key

    1 拿到ip地址 扫端口 扫目录不多说 有1443端口 SQL sever数据库 和27666端口 2 扫出来这个地址 查看一下 访问一下 发现一个是后台 一个存在文件包含的网页 一个大概是上传地址 爆破一下后台发现不成功 试一下利用文件包
  • 虚拟主机的配置

    root localhost nmcli connection modify ens160 ipv4 addresses 192 168 171 137 24 root localhost nmcli connection up ens16
  • 21天Jenkins打卡Day15项目复制

    参考文章 http istester com jenkins 188 html
  • 【visual studio】使用 C++ OpenCV 读取图片失败,数据为空

    这里写自定义目录标题 图片路径问题 图片路径问题 F Documents test image Image BMP 需要改成 F Documents test image Image BMP
  • feign调用第三方接口服务

    前言 做个笔记 下次直接抄 这里需要拿到response的header做验签之类的操作 所以用feign Response来接收响应 正文 第三方接口调用的feign 自测OK import com mea pay common excep
  • 广告案例|10亿数据、查询<10s,论基于OLAP搭建广告系统的正确姿势

    由于流量红利逐渐消退 越来越多的广告企业和从业者开始探索精细化营销的新路径 取代以往的全流量 粗放式的广告轰炸 精细化营销意味着要在数以亿计的人群中优选出那些最具潜力的目标受众 这无疑对提供基础引擎支持的数据仓库能力 提出了极大的技术挑战
  • Google 每天处理约 20000TB 的数据

    Google 热衷于处理全球的信息 每天 他们花费大量时间探索更好的信息整理技术 他们目前使用的技术为 MapReduce 这是一种可以对数据进行并发处理的软件架构 鉴于其简单性与处理大规模数据的能力 MapReduce 是 Google
  • SpringBoot+vue(MyBatis + Shiro + Jwt + Druid + Redis + ElementUI )快速开发框架

    Jeebase 项目介绍 Jeebase是一款前后端分离的开源开发框架 基于springboot vue vue element admin 开发 二期会整合react前端框架Ant Design React 在实际应用中已经使用这套框架开
  • 1188C语言实验——各位数字之和排序

    题目描述 给定n个正整数 根据各位数字之和从小到大进行排序 输入 输入数据有多组 每组数据占一行 每行的第一个数正整数n 表示整数个数 后面接n个正整数 当n为0时 不作任何处理 输入结束 输出 输出每组排序的结果 示例输入 2 1 2 3
  • Using Field in Searching(使用字段搜索)

    Task 1 Use the Fields sidebar to examine search results In the app navigation bar i e the bar towards the top of the bro
  • React 从零开始学习(九)—— 落子有悔

    到目前为止 demo 的操作是不能回退的 点击格子以后 想要记录历史的操作 就需要 使用 slice 函数为每一步创建 squares 数组的副本 同时把这个数组当作不可变对象 这样就可以把所有 squares 数组的历史版本都保存下来了
  • 四大作用域

    四大作用域解读 1 page指当前页面有效 在一个jsp页面里有效 代表当前的jsppageContext 提供了获取 其他8大隐式对象的方法域对象setAttribute String name Object value 2 reques
  • Android面试家常菜:Handler消息机制全家桶一把梭,看完这篇还不懂,请砍我

    前言 Handler可以说小伙伴们用的非常多了 可以说Handler是支撑整个Android系统运行的基础 本质上Android系统都是由事件驱动的 而处理事件的核心就在于Handler 接下来我们就从简单的使用 到源码分析让你彻彻底底明白
  • Python 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

    给定排序数组和目标值 如果找到目标 则返回索引 如果没有 请返回索引按顺序插入的索引 您可以假设数组中没有重复项 Example 1 Input 1 3 5 6 5 Output 2 Example 2 Input 1 3 5 6 2 Ou
  • Axure实现弹框周围遮罩效果

    每一次我都惊叹知识的浩瀚和多彩 在IT这个所做即所得的世界里 很容易获得成就感 当然也时时刻刻活在对大神的膜拜之中 就以这次的原型图制作来说 我们遇到了很多的问题 自己实现了很多功能 但是今天晚上大家对自己原型图的演示和分享之中 又让我感叹
  • 2022年全国大学生数学建模竞赛赛题B组解题参考+代码

    题目 获取题目方式 2022年全国大学生数学建模竞赛题目 代码思路获取方式 关注博主竞赛专栏 B 题 无人机遂行编队飞行中的纯方位无源定位 无人机集群在遂行编队飞行时 为避免外界干扰 应尽可能保持电磁静默 少向外发射电磁波信号 为保持编队队
  • VMware 使用U盘装系统

    第一步 首先要有U盘 把这个U盘制作成启动盘教程中使用的是大白菜 大白菜下载地址 第二步 打开你的VMware 新建一个虚拟盘机 第三步 选择稍后安装系统 第四步 选择你要安装的系统 第五步 是你给虚拟机命名和选择安装路径最好不要放在C盘里
  • C++第六章:选择结构的程序设计

    一 选择语句 1 if语句 if语句的作用是计算给定的表达式 根据判断结果选择执行相应的语句 形式1 if 表达式 语句1 例 int a 5 b 1 t if a gt b t a a b b t 形式2 if 表达式 语句1 else
  • Ubuntu-22.04通过RDP协议连接远程桌面

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 RDP是什么 二 配置 1 打开远程桌面功能 2 验证服务 3 防火墙配置 4 测试效果 总结 前言 由于一些特殊需要 我需要通过远程桌面连接到Ubunt
  • 0-1背包问题和完全背包问题

    先总体介绍一下0 1背包和完全背包的区别 主要是01背包和完全背包 背包九讲里面的其他背包问题 都是竞赛级别的 leetcode上面没有 01背包就是 背包存在一个最大容量V 每个物品有两个参数 体积w和价值v 目的是在不超过背包最大容量的