Hdu2602-Bone Collector(01背包问题)

Hdu2602-Bone Collector(01背包问题)

  • 01背包递归写法(记忆化)
  • 二维dp
  • 一维dp

01背包递归写法(记忆化)

递归的思想就是:

  • 我要计算的是从第0号物体到n-1号物体的最大重量;
  • 记录一个当前判断到i号物体时,已经选择的物体的容量curW;
  • 我的递归边界是如果判断到当前的物体大于我的背包容量了,这个物体就不能选,于是我之前如果假设选了的话我就要减掉这个物体的价值;
  • 如果i越界的话就返回0;
  • 否则我就递归的去求选择了i号物品的最大值和不选择i号物品的最大值中,我们要取的最大值;
    public static int maxValue(int[] w,int[] v,int C){
        return process(w,v,0,0,C);
    }
    private static int process(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(process(w,v,i+1, curW+w[i],C)+v[i],
                process(w,v,i+1,curW,C));
    }

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

import java.io.BufferedInputStream;
import java.util.Arrays;
import java.util.Scanner;

public class Main {

    public static int[][] map;
    public static int maxValue(int[] w,int[] v,int C){
        map = new int[w.length + 1][C + 1];
        for(int i = 0; i < w.length + 1; i++){
            Arrays.fill(map[i],-1);
        }
        return process(w,v,0,0,C);
    }
    private static int process(int[] w, int[] v, int i, int curW, int C) {
        if(curW > C)
            return -v[i-1];
        if(i == w.length)
            return 0;
        if(map[i][curW] != -1) //记忆化
            return map[i][curW];
        map[i][curW] = Math.max(process(w,v,i+1, curW+w[i],C)+v[i],
                process(w,v,i+1,curW,C));
        return map[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 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 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--) //万万不可

这里写图片描述


猜你喜欢

转载自blog.csdn.net/zxzxzx0119/article/details/82530940