算法练习:从暴力递归到动态规划3

本文介绍了解决背包问题的两种方法:暴力递归和动态规划。首先通过暴力递归来寻找问题的解,然后优化为动态规划解决重复计算的问题。文章详细解释了每种方法的实现过程,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

背包问题:

暴力递归

动态规划

往期回顾:


背包问题:

给定一个商品重量数组weight[] , 所对应的价值数组value[] ,背包容量为bag (均为int整形)。

weight >= 0,value >= 0 ;

试问: 背包中所能装下的商品的最大价值和是多少?

思路:先用暴力递归的方法写出问题的尝试函数,通过尝试函数去套解动态规划问题。

暴力递归

        我们可以用一个索引index,自左向右依次遍历商品;每遍历到一个商品时,该商品有且仅有 要或者不要 两种情况。递归并返回两种情况的最大值。

这里有几个值得注意的地方:

  • 当背包剩余容量 rest<0 时:返回0;

  • 当索引越界时:返回0;

  • 当背包的容量 rest>0 但不足以装下当前商品时:放弃该商品;

代码如下:

		//主方法
	public static int BagPro (int weight[], int value[], int bag) {
        if (weight==null || value == null || weight.length != value.length || weight.length==0) {
            return 0;
        }
        return process(weight,value,0,bag);
    }
    	//子方法
    public static int process (int weight[], int value[], int index, int rest) {
        //剩余容量小于0
        if (rest < 0) {
            return 0;
        }
        //索引越界
        if (index == weight.length) {
            return 0;
        }
        //不要该物品
        int p1 = process(weight,value,index+1,rest);
        //要该物品:先判断背包容量是否够,不够返回0;
        int p2 = 0;
        int next = rest-weight[index] < 0 ? -1 : value[index];
        //若背包容量够,返回当前value并调用下一个商品做判断。
        if (next != -1) {
            p2 = next + process(weight,value,index+1,rest-weight[index]);
        }
        //返回一个最大value和。
        return Math.max(p1,p2);
    }

测试:

	public static void main(String[] args) {
        int[] weight = {2,4,1,2,3};
        int[] value = {5,1,6,1,2};
        System.out.println(BagPro(weight,value,11));
        System.out.println(dp(weight,value,11));
    }
    //结果
    14
	14

动态规划

        由于暴力递归的过程中存在重复解,因此可以对上述代码进行优化。写出暴力递归的尝试函数后,只需要将尝试函数作为动态规划中“缓存表”的添值方法,写出“缓存表”,即可轻松得到此背包问题的动态规划解法。

        分析:在这个问题中,索引index 和 背包剩余容量rest 的值是动态变化的,因此以二者的取值范围为基础建立一张dp表,返回index==0,rest==

  • index:0~weight.length(越界)
  • rest:负值~bag(最大容量)
	//背包问题——动态规划
    public static int dp (int weight[], int value[], int bag) {
        if (weight==null || value == null || weight.length != value.length || weight.length==0) {
            return 0;
        }
        int N = weight.length;
        //创建dp表
        int[][] dp = new int[N+1][bag+1];
        //填表
        for (int index = N-1; index >=0; index--) {
            for (int rest = 0; rest <= bag; rest++) {
                //不拿该商品
                int p1 = dp[index+1][rest];
                //拿该商品
                int p2 = 0;
                //判断背包容量是否够
                int next = rest-weight[index]< 0 ?
                    -1 : dp[index+1][rest-weight[index]];
                if (next != -1) {
                    p2 = value[index] + next;
                }
                dp[index][rest] = Math.max(p1,p2);
            }
        }
        return dp[0][bag];
    }

测试:

	public static void main(String[] args) {
        int[] weight = {2,4,1,2,3};
        int[] value = {5,1,6,1,2};
        System.out.println(BagPro(weight,value,11));
        System.out.println(dp(weight,value,11));
    }
    //输出:
    14
	14

往期回顾:



算法练习:从暴力递归到动态规划1

算法练习:从暴力递归到动态规划2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

superzheng__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值