Hdu - 2602. Bone Collector(01背包问题)

本文深入解析01背包问题的递归、二维动态规划及一维动态规划解法,通过Hdu-2602.BoneCollector题目实例,详细阐述每种方法的实现过程和优化策略。

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

Hdu - 2602. Bone Collector(01背包问题)

  • 递归写法
  • 二维dp
  • 一维dp

题目链接

递归写法

递归的思想就是:

  • 我要计算的是从第0号物体到n-1号物体的最大重量;
  • 记录一个当前判断到i号物体时,已经选择的物体的容量curW
  • 我的递归边界是如果判断到当前的物体大于我的背包容量了,这个物体就不能选,于是我之前如果假设选了的话我就要减掉这个物体的价值;
  • 如果i越界的话就返回0
  • 否则我就递归的去求选择了i号物品的最大值和不选择i号物品的最大值中,我们要取的最大值;
public class Main {

    static int maxValue(int[] w, int[] v, int C) {
        return rec(w, v, 0, 0, C);
    }

    static int rec(int[] w, int[] v, int i, int curW, int C) {
        if (curW > C)
            return -v[i - 1];  //累加和为0
        if (i == w.length) //到最后一个
            return 0;
        return Math.max(rec(w, v, i + 1, curW + w[i], C) + v[i],
                rec(w, v, i + 1, curW, C));
    }
}

但是上面的写法会超时,所以我们需要使用一个二维数组来记录计算过的重复子问题。(也就是记忆化)

import java.io.BufferedInputStream;
import java.util.*;

public class Main {

    static int[][] dp;

    static int maxValue(int[] w, int[] v, int C) {
        dp = new int[w.length + 1][C + 1];
        for (int i = 0; i < w.length + 1; i++)
            Arrays.fill(dp[i], -1);
        return rec(w, v, 0, 0, C);
    }

    static int rec(int[] w, int[] v, int i, int curW, int C) {
        if (curW > C)
            return -v[i - 1];
        if (i == w.length)
            return 0;
        if (dp[i][curW] != -1) //记忆化
            return dp[i][curW];
        dp[i][curW] = Math.max(rec(w, v, i + 1, curW + w[i], C) + v[i],
                rec(w, v, i + 1, curW, C));
        return dp[i][curW];
    }

    public static void main(String[] args) {

        Scanner cin = new Scanner(new BufferedInputStream(System.in));
        int T = cin.nextInt();
        while (T-- > 0) {
            int n = cin.nextInt();
            int C = cin.nextInt();
            int[] w = new int[n];
            int[] v = new int[n];
            for (int i = 0; i < n; i++) v[i] = cin.nextInt();
            for (int i = 0; i < n; i++) w[i] = cin.nextInt();
            System.out.println(maxValue(w, v, C));
        }
    }
}

二维dp

这里写图片描述
这里写图片描述
(输入就不处理了,和上面的一样)

public class Main {

    static int maxValue(int[] w, int[] v, int C) {
        int[][] dp = new int[w.length + 1][C + 1];
//        for (int j = 0; j <= C; j++) dp[w.length][j] = 0; //auto initialize to 0
        for (int i = w.length - 1; i >= 0; i--) {
            for (int j = C; j >= 0; j--) {
                dp[i][j] = j + w[i] > C ? dp[i + 1][j] : Math.max(dp[i + 1][j], dp[i + 1][j + w[i]] + v[i]);
            }
        }
        return dp[0][0];
    }
}

一维dp

也就是滚动优化,dp用来记录列。

public class Main {

    static int maxValue(int[] w, int[] v, int C) {
        int[] dp = new int[C + 1];
        for (int i = w.length - 1; i >= 0; i--) {
            for (int j = 0; j <= C; j++) {
                dp[j] = j + w[i] > C ? dp[j] : Math.max(dp[j], dp[j + w[i]] + v[i]);
            }
        }
        return dp[0];
    }
}
  • 这一行代码for (int j = 0; j <= C; j++) 千万不能写成下面的样子(也就是不能和二维dp一样从C --> 0):
  • 因为这样的话我们的需要的dp[j + w[i]]此时已经更新了,不是我们需要的了。
  for (int j = C; j >= 0 ; j--) //万万不可

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值