动态规划——01背包

物有本末 事有始终
‘’每件事情都有开始和终结,我们本就该用现在累计的资本去渲染未来‘’
在这里插入图片描述

前言

在学习该算法之前我需要提醒一下大家,很多大佬都说背包问题是学习动态规划的基础,这可能会让一些小伙伴误认为如果要学习动态规划就必须先学习背包问题。实则不然,背包问题只是动态规划中的一个比较典型类型的问题而已,至于为什么说学习动态规划规就要弄明白背包问题,是因为背包问题可以更好的将动态规划的用法及优势展现出来,这样更方便我们理解。


一、何为算法

动规算是算法体系中最难攻克的一个算法之一,但是也不需要过于担忧,因为算法之所以难学只是因为我们需要将一个问题抽象化的构建在自己脑海中然后再分析这个问题的原理及运算模式,直到将这个问题梳理完成后才能去计算机中验证,这样就无法很清晰的理解这个问题。但是任何问题都是源于生活的,算法亦是如此,算法只是为了让计算机更好的帮助我们解决问题,我们只需要将一个计算机的问题联系到现实生活中,用现实生活中的想法去解决它就可以了。而背包问题解决的便是资源利用最大化的问题。

二、01背包问题

有 N件物品和一个容量是 V的背包。每件物品只能使用一次。

第 i 件物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式

第一行两个整数,N,V
,用空格隔开,分别表示物品数量和背包容积。

接下来有 N
行,每行两个整数 vi,wi
,用空格隔开,分别表示第 i
件物品的体积和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

0<N,V≤1000

0<vi,wi≤1000

输入样例

4 5
1 2
2 4
3 4
4 5
输出样例:

8

三、01背包的原理及图表解释

在其上说过背包问题就是资源利用最大化的问题,在该题中验证一下:

  1. 根据题意我们可以知道,我们有的资源是一个容量为V的背包
  2. 一共是N件物品,他们分别有自己的价值和需要占用的体积
  3. 我们需要尽可能的利用我们的体积V得到最大价值Max w

至于现实问题也是很好找的:
每当月末没有生活费的时候,你就会考虑20块钱如何用一周,这里就用到了背包问题。
“如何用20元换来最大的饱腹感”

图表解释:
在这里插入图片描述
在这里插入图片描述

四、01背包源代码

import java.util.*;
	public class Main{
	    //定义全局数组默认值为0
	static int N = 1010;
	static int[][] dp = new int[N][N];  //统计不同容量时的最大价值
	static int[] v = new int[N];//存放物品体积
	static int[] w = new int[N];//存放物品价值
	public static void main(String[] args){
	    Scanner sc = new Scanner(System.in);
	    int m = sc.nextInt();
	    int n = sc.nextInt();
	for(int i=1;i<=m;i++)
	{
	    v[i] = sc.nextInt();
	    w[i] = sc.nextInt();
	}
	    for(int i=1;i<=n;i++)
	    for(int j=1;j<=m;j++)
	{ 
	    dp[i][j] = dp[i][j-1];//默认值为前一个值
	    if(i>=v[j]) //如果此时的容量大于体积就进行比较
	        dp[i][j] = Math.max(dp[i][j],dp[i-v[j]][j-1]+w[j]);
	}
	System.out.println(dp[n][m]);
	}
	}

五、01背包进阶代码及图表

图表解释:
在这里插入图片描述

注:虽然进阶版的01背包也是用二维表表示,但是本质上区别明显。写成二维表的形式只是为了更好的表达出其含义。
随着循环的运算每轮运算的数值也将逐渐减少,从容量5-容量1,容量5-容量2…因为v[i]在这个过程中会不断增大所以也会筛选掉不符合要求的数据。
而小伙伴们在进阶中遇到最大的疑问可能也是为什么判断条件是“j=m;j>=v;j–”而非“j=v[i];j<=m;j++”。在此其实也是在上面讲到过的,我们计算是的物品的价值而不是背包容量的最大价值,希望大家能够分清

import java.util.*;
public class Main{
    public static void main(String[] args)
    {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int P = 1010;
        int[] v = new int[P];
        int[] w = new int[P];
        int[] dp = new int[P];
        
        for(int i=1;i<=n;i++)
            {
                v[i] = sc.nextInt();
                w[i] = sc.nextInt();
            }
        for(int i=1;i<=n;i++)  
          for(int j=m;j>=v[i];j--) 
            {
                    dp[j] = Math.max(dp[j],dp[j-v[i]]+w[i]);
                }
System.out.println(dp[m]);
}
    
}

六、拓展及延伸


45-跳跃游戏II
62-不同路径
72-编辑距离

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值