豆芽菜的背包问题学习

背包问题

01背包问题

二维求解
/**
 * 01 背包问题
 * 物品只能选择一次
 *
 * 二维dp dp[n][m] 使用m价值 购买n件的最高价值
 *
 * 1、dp[i-1][j] 第i件不购买
 * 2、dp[i-1][j - v[i]] + w[i] 购买第i件
 * 状态转移方程 dp[i][j] = max(dp[i-1][j], dp[i-1][j - v[i]] + w[i])
 *
 * 初始化 dp[n][m] 初始化为0 表示未进行购买
 */


public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String[] input = in.nextLine().split(" ");
        int n = Integer.parseInt(input[0]);
        int m = Integer.parseInt(input[1]);

        int[][] dp = new int[n + 1][m + 1];

        int[] v = new int[n + 1];
        int[] w = new int[n + 1];
        for(int i = 1; i <= n; i++){
            input = in.nextLine().split(" ");
            v[i] = Integer.parseInt(input[0]);
            w[i] = Integer.parseInt(input[1]);
        }

        for(int i = 1; i <= n; i++){
            for(int j = 0; j <= m; j ++){
                dp[i][j] = dp[i - 1][j];
                if(j >= w[i]){
                    dp[i][j] = Math.max(dp[i][j], dp[i-1][j - v[i]] + w[i]);
                }
            }
        }

        System.out.println(dp[n][m]);
    }
}
一维求解
import java.util.Scanner;

public class Main {
    /**
     * 01背包降维
     *
     * dp[m] 表示 使用体积,能够购买到的最大价值
     *
     * 1、 dp[j] 表示不进行购买第i件商品
     * 2、dp[j - v[i]] + w[i] 表示购买第i件商品
     * 
     * 状态转移方程
     * dp[j] = max(dp[j], dp[j - v[i]] + w[i])
     *
     * 初始化 为0
     */

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String[] input = in.nextLine().split(" ");
        int n = Integer.parseInt(input[0]);
        int m = Integer.parseInt(input[1]);

        int[] dp = new int[m + 1];

        int[] v = new int[n + 1];
        int[] w = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            input = in.nextLine().split(" ");
            v[i] = Integer.parseInt(input[0]);
            w[i] = Integer.parseInt(input[1]);
        }

        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]);
    }
}

完全背包问题

一维求解
import java.util.Scanner;


public class Main {
    /**
     * 完全背包问题
     *
     * 状态转移方程
     * dp[j] = max(dp[j], dp[j - v[i]] + w[i])
     *
     */

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String[] input = in.nextLine().split(" ");
        int n = Integer.parseInt(input[0]);
        int m = Integer.parseInt(input[1]);

        // 表示使用体积 能够购买到的最大价值
        int[] dp = new int[m + 1]; 

        for (int i = 1; i <= n; i++) {
            input = in.nextLine().split(" ");
            int v = Integer.parseInt(input[0]);
            int w = Integer.parseInt(input[1]);
            // 循环遍历 多次购买 
            for(int j = v; j <= m; j++){
                dp[j] = Math.max(dp[j], dp[j - v] + w);
            }
        }
		// 最优解为dp数组最后一项
        System.out.println(dp[m]);
    }
}

多重背包问题

1、遍历求解
import java.util.Scanner;


public class Main {
    /**
     * 多重背包问题
     * 将购买次数平铺等价于01背包问题
     *
     * 状态转移方程
     * dp[j] = max(dp[j], dp[j - v[i]] + w[i])
     *
     */

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String[] input = in.nextLine().split(" ");
        int n = Integer.parseInt(input[0]);
        int m = Integer.parseInt(input[1]);

        // 表示使用体积 能够购买到的最大价值
        int[] dp = new int[m + 1]; 

        for (int i = 1; i <= n; i++) {
            input = in.nextLine().split(" ");
            int v = Integer.parseInt(input[0]);
            int w = Integer.parseInt(input[1]);
            int s = Integer.parseInt(input[2]);
            // 类比于01背包问题遍历数组由m开始
            for(int j = m; j >= v; j--){
               	// 将购买次数平铺为 体积为 k * v 价值为 k * w的购买次数
                for(int k = 1; k <= s && k * v <= j; k++){
                    dp[j] = Math.max(dp[j], dp[j - k * v] + k * w);
                }
            }
        }
        // 最优解于dp数组最后一项
        System.out.println(dp[m]);
    }
}
2、二进制优化
import java.util.Scanner;


public class Main {
    /**
     * 多重背包问题
     * 将购买次数平铺等价于01背包问题
     * 
     * 采用二进制展开次数s, 二进制展开能表示s以下任何数
     *
     * 状态转移方程
     * dp[j] = max(dp[j], dp[j - v[i]] + w[i])
     *
     */
     
    private static int LENGTH = 100010;

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String[] input = in.nextLine().split(" ");
        int n = Integer.parseInt(input[0]);
        int m = Integer.parseInt(input[1]);

        // 表示使用体积 能够购买到的最大价值
        int[] dp = new int[LENGTH];

        int[] V = new int[LENGTH];

        int[] W = new int[LENGTH];

        int index = 1;
        for (int i = 1; i <= n; i++) {
            input = in.nextLine().split(" ");
            int v = Integer.parseInt(input[0]);
            int w = Integer.parseInt(input[1]);
            int s = Integer.parseInt(input[2]);
            // 二进制展开 
            int j = 1;
            while(j <= s){
                V[index] = v * j;
                W[index] = w * j;
                s -= j;
                j = j * 2;                
                index++;
            }
            if (s > 0) {
                V[index] = v * s;
                W[index] = w * s;
                index++;
            }
        }
        for (int i = 1; i < index; 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]);
    }
}
posted @ 2025-06-18 10:00  Bean_sprout  阅读(9)  评论(0)    收藏  举报