背包问题 0-1背包 完全背包 多重背包

区分
默认背包问题都先遍历物品(物品重量)再遍历背包(背包大小)但是不绝对 0-1背包问题遍历背包时逆序, 完全背包问题遍历背包时正序 求最大价值,dp初始值就小点(一般0就行),求最小价值,dp初始值就大点(找个数 Interger最大值或者背包大小+1W这种)
完全背包中 如果求组合数(顺序无关,1+5,5+1 算一种 循环中只会遍历到5+1)就是外层for循环遍历物品,内层for遍历背包。 如果求排列数(顺序相关,1+5,5+1 算两种,循环中1+5,5+1都会遍历到)就是外层for遍历背包,内层for循环遍历物品。
0-1背包是 一个背包里每个物品最多能放一次
完全背包是 一个背包里每个物品可以放多次
如果是求价值的最大值的往往递推公式是dp[j] = Math.max(dp[j],dp[j - weight[i]] + value[i]);这种每次把当前物品的重量减去再加上当前物品的价值
如果是求达到固定价值的方案个数的话往往递推公式是dp[j] += dp[j - coins[i]]; 这种求当前j背包重量下的方案个数,需要把dp[j](代表不考虑当前物品时的)+dp[j - coins[i]](代表考虑了当前物品并且有多少种方案加上当前物品正好能达到j这个背包容量(类似于爬楼梯))
多重背包就是在0-1背包的基础上,在循环内部在加一层循环这个物品数量的for循环。
0-1背包
https://kamacoder.com/problempage.php?pid=1046

public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int M = sc.nextInt();
        int N = sc.nextInt();
        int[] weight = new int[M];
        int[] value = new int[M];
        for (int i = 0; i < M; i++) {
            weight[i] = sc.nextInt();
        }
        for (int i = 0; i < M; i++) {
            value[i] = sc.nextInt();
        }
        int[] dp = new int[N+1];
        //且初始化全是0
        for (int i = 0; i < M; i++) {//一共M个物品 挨个轮
            for (int j = N; j >= weight[i] ; j--) {//逆序遍历 这个物品放进来没超上限时,就可以试试看合不合理,每次让背包上限--
                dp[j] = Math.max(dp[j],dp[j - weight[i]] + value[i]);
            }
        }
        System.out.println(dp[N]);
    }

总结: dp[j]的含义是 用i以及i以前的物品去放的最大价值 j >= weight[i]说明j容量能放下i物品,那就判断不放i的时候和拿出来一个i的空去放i的时候哪个价值更高。 0-1背包遍历背包时逆序
完全背包
https://kamacoder.com/problempage.php?pid=1052

public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        int V = sc.nextInt();
        int[] weight = new int[N];
        int[] value = new int[N];
        for (int i = 0; i < N; i++) {
            weight[i] = sc.nextInt();
            value[i] = sc.nextInt();
        }
        //初始值dp都为0  求最大价值,每一步用max,初始为小点
        int[] dp = new int[V+1];
        for (int i = 0; i < N; i++) {//一共N个物品。挨个轮
            for (int j = weight[i]; j <= V ; j++) {//重量比背包上限小,就可以试试看放这个物品合不合理,每次让物品重量++
                dp[j] = Math.max(dp[j],dp[j - weight[i]] + value[i]);
            }
        }
        System.out.println(dp[V]);
    }

总结: 完全背包问题,dp[j]代表用i物品以及i之前的物品去放的最大价值,,完全背包,所以遍历背包时正序。
多重背包
https://kamacoder.com/problempage.php?pid=1066

public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int c = sc.nextInt();
        int n = sc.nextInt();
        int[] weight = new int[n];
        int[] value = new int[n];
        int[] nums = new int[n];
        for (int i = 0; i < n; i++) {
            weight[i] = sc.nextInt();
        }
        for (int i = 0; i < n; i++) {
            value[i] = sc.nextInt();
        }
        for (int i = 0; i < n; i++) {
            nums[i] = sc.nextInt();
        }
        int[] dp = new int[c+1];
        for (int i = 0; i < n; i++) {//遍历物品
            for (int j = c; j >= weight[i] ; j--) {//遍历背包
                //0-1背包的基础上加上一个遍历数量的操作
                for (int k = 1; k <= nums[i]; k++) {
                    if (j - k * weight[i] >= 0){
                        dp[j] = Math.max(dp[j],dp[j-k*weight[i]] + k*value[i]);
                    }
                }
            }
        }
        System.out.println(dp[c]);
    }

总结:完全背包就是在0-1背包的基础上加了一层遍历物品数量的操作。

posted @ 2024-03-29 13:59  jeasonGo  阅读(108)  评论(0)    收藏  举报