首页 > 其他分享 >【DP】01背包与完全背包总结及空间优化

【DP】01背包与完全背包总结及空间优化

时间:2023-07-16 23:01:07浏览次数:46  
标签:件物品 01 int 背包 DP var new dp

01背包问题

题目描述:有n件物品,每件物品的重量为w[i],价值为c[i]。现在有一个容量为V的背包,问怎么选取物品放入背包,能使得背包内的总价值最大。其中每件物品只能放入一次。

样例

n = 5, V =8
w[i] = 3, 5, 1, 2, 2
c[i] = 4, 5, 2, 1, 3

分析:使用暴力的解法,每件物品分为放入、不放入,因此复杂度为O(2^n)。因此考虑使用动态规划的方法,设dp[i][j]表示选择前i件物品,重量恰好为j的最大价值,则易得:

​ dp[i][j] = max { dp[i-1][j], dp[i-1][j-w[i]] + c[i] }

  • 不选此物品,则价值最大值为 前i-1件物品、容量j的价值
  • 选择此物品,则价值最大值为 前i-1件物品、容量j - 当前物品重量 w[i] 加上当前物品的价值
  • 两种情况的最大值即为前i件物品,重量恰好为j的最大价值
二维dp写法
public static void main(String[] args) {
    var w = new int[]{1, 3, 4};
    var v = new int[]{15, 20, 30};
    int n = w.length;
    int V = 4;

    var dp = new int[n][V+1];
    for(int j = w[0]; j <= V; j++) {
        dp[0][j] = v[0];
    }
    for(int i = 1; i < n; i++) {
        for(int j = 1; j <= V; j++) {
            if(j-w[i] < 0) {
                dp[i][j] = dp[i-1][j];
            } else {
                dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]);
            }
        }
    }

    for(var row : dp) {
        System.out.println(Arrays.toString(row));
    }
}
一维滚动数组写法
	public static void main(String[] args) {
        var w = new int[]{1, 3, 4};
        var v = new int[]{15, 20, 30};
        int n = w.length;
        int V = 4;

        var dp = new int[V+1];
        for(int j = w[0]; j <= V; j++) {
            dp[j] = v[0];
        }

        for(int i = 1; i < n; i++) {
            for(int j = V; j >= w[i]; j--) {
                dp[j] = Math.max(dp[j], dp[j-w[i]] + v[i]);
            }
        }

        System.out.println(Arrays.toString(dp));
    }

一维滚动数组的写法只能是倒序

​ 如果是正序的话,dp[1] = dp[1 - weight[0]] + value[0] = 15

​ dp[2] = dp[2 - weight[0]] + value[0] = 30

​ 即重量为2的dp值使用了重量为1的dp值(这个值已经添加了一次物品),因此为了保证只使用一次物品,要倒序遍历(保证前面的dp值没有更新,即没有添加当前物品

​ 当然正序的做法也恰好能用于完全背包问题

完全背包问题

题目描述:有n件物品,每件物品的重量为w[i],价值为c[i]。现在有一个容量为V的背包,问怎么选取物品放入背包,能使得背包内的总价值最大,其中每件物品有无数件

样例

n = 5, V =8
w[i] = 3, 5, 1, 2, 2
c[i] = 4, 5, 2, 1, 3

分析:使用暴力的解法,每件物品分为放入、不放入,因此复杂度为O(2^n)。因此考虑使用动态规划的方法,设dp[i][j]表示选择前i件物品,重量恰好为j的最大价值,则易得:

	dp[i][j] = max { dp[i-1][j], dp[i][j-w[i]] + c[i] }

​ 对比01背包问题

	dp[i][j] = max { dp[i-1][j], dp[i-1][j-w[i]] + c[i] }
  • 不选此物品,则价值最大值为 前i-1件物品、容量j的价值
  • 选择此物品,则价值最大值为 前i件物品(允许再次选择第i件)、容量j - 当前物品重量 w[i] 加上当前物品的价值
  • 两种情况的最大值即为前i件物品,重量恰好为j的最大价值
二维dp写法
public static void main(String[] args) {
    var w = new int[]{1, 3, 4};
    var v = new int[]{15, 20, 30};
    int n = w.length;
    int V = 4;

    var dp = new int[n][V+1];
    for(int j = w[0]; j <= V; j++) {
        dp[0][j] = v[0];
    }
    for(int i = 1; i < n; i++) {
        for(int j = 1; j <= V; j++) {
            if(j-w[i] < 0) {
                dp[i][j] = dp[i-1][j];
            } else {
                dp[i][j] = Math.max(dp[i-1][j], dp[i][j-w[i]] + v[i]);
            }
        }
    }

    for(var row : dp) {
        System.out.println(Arrays.toString(row));
    }
}

标签:件物品,01,int,背包,DP,var,new,dp
From: https://www.cnblogs.com/tod4/p/17558787.html

相关文章

  • [SDOI2010] 外星千足虫
    题意现在你面前摆有\(1\ldotsN\)编号的\(N\)只千足虫,你的任务是鉴定每只虫子所属的星球,但不允许亲自去数它们的足。Charles每次会在这\(N\)只千足虫中选定若干只放入“昆虫点足机”(theInsectFeetCounter,IFC)中,“点足机”会自动统计出其内所有昆虫足数之和。Charles......
  • ThreadPoolTaskExecutor自定义线程池的配置和使用
    ThreadPoolTaskExecutor自定义线程池的配置和使用线程池ThreadPoolTaskExecutor和ThreadPoolExecutor的区别ThreadPoolExecutor,这个类是JDK中的线程池类,继承自Executor,里面有一个execute()方法,用来执行线程,线程池主要提供一个线程队列,队列中保存着所有等待状态的线程,避免了创......
  • A014 《太阳系的秘密》编程 源码
    一、课程介绍在本节课中,将会了解太阳系的基本情况,绘制出一个太阳系。在这个过程中,理解for循环结合列表的使用方法,掌握使用random.randint(a,b)产生随机整数的方法。二、知识重难点解析利用列表实现for循环将for循环后边的range()替换成列表后,for循环会按顺序依次提取列......
  • 背包之专题
    P1282多米诺骨牌-洛谷|计算机科学教育新生态(luogu.com.cn)第一题一道思维题 设dis=a[i]−b[i]f[i][j+dis+N]=min(f[i][j+dis+N],f[i−1][j+N]);//不反转f[i][j+dis+N]=min(f[i][j+dis+N],f[i−1][j+N]+1);//反转f[i][j+N]=min(f[i−1][j−dis+N],f[i−1][j+dis+N]+1......
  • 【贪心】AGC018C Coins
    ProblemLink现在有\(X+Y+Z\)个人,第\(i\)个人有三个权值\(a_i,b_i,c_i\),现在要求依次选出\(X\)个人,\(Y\)个人和\(Z\)个人(一个人只能选依次),使得这\(X\)个人的\(a\)权值,\(Y\)个人的\(b\)权值,\(Z\)个人的\(c\)权值之和最大。\(X,Y,Z\le10^5\)。技巧:排序证明......
  • 仿微信聊天程序 - 01. 开篇
    本文是仿微信聊天程序专栏的第一篇文章,主要简要说明仿微信聊天程序的功能需求及架构设计。仿微信聊天程序专栏主要记录了使用JavaFX+Netty开发仿微信聊天程序---米虫IM。功能需求米虫IM已经完成的功能如下:用户注册功能用户登录功能搜索好友功能添加好友功能文本聊天......
  • CVE-2019-11043(PHP远程代码执行漏洞)复现
    一、漏洞介绍1、相关背景在web早期,页面都是以静态页面为主(如:HTML),没有动态页面的说法,所有还没有动态语言(如:PHP、JSP等)后来Ngnix为支持PHP语言就将有出现php页面的请求给PHP相关程序来进行处理,然后将处理后的结果反馈给用户。而解决PHP的相关程序就是cgi协议,有了cgi协议以后......
  • 【网络】【TCP】如何基于 UDP 协议实现可靠传输?
    1  前言这节我们来看个问题,就是 TCP协议有什么缺陷?很多同学第一反应就会说把TCP可靠传输的特性(序列号、确认应答、超时重传、流量控制、拥塞控制)在应用层实现一遍。实现的思路确实这样没错,但是有没有想过,既然TCP天然支持可靠传输,为什么还需要基于UDP实现可靠传输呢?这......
  • android:padding="15dp
    Android中的padding属性解析在Android开发中,我们经常会使用到布局文件来定义界面的结构和外观。其中,android:padding属性是一个非常常见的属性之一,用于设置控件的内边距。本篇文章将为大家介绍android:padding属性的使用方法以及相关知识点。1.android:padding属性的作用androi......
  • BUU Re childRe 和 [SWPU2019]ReverseMe
    childRe  符号生成规则:C++函数符号生成规则:private:char*__thiscallR0Pxx::My_Aut0_PWN(unsignedchar*)得到?My_Aut0_PWN@ROPxx@@AAEPADPAE@Z 二叉树:下面给出实操(如何利用这个对应关系): 以及列表下标的应用:主要是indexa=list("1234567890-=!@#$%^&*()_+qw......