「背包问题专题 1」之「0-1 背包问题」

第 1 版:使用二维数组,不设置「哨兵」行

Java 代码:

import java.util.Scanner;

public class Main {

    // 0-1 背包问题
    // 判题地址:https://www.acwing.com/problem/content/description/2/

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读第 1 行
        int N = scanner.nextInt();
        int V = scanner.nextInt();

        // 读后面的体积和价值
        int[] weight = new int[N];
        int[] value = new int[N];

        for (int i = 0; i < N; i++) {
            weight[i] = scanner.nextInt();
            value[i] = scanner.nextInt();
        }

        // 因为包含 0,所以 + 1
        int[][] dp = new int[N][V + 1];


        // 先写第 1 行
        for (int j = 1; j <= V; j++) {
            // 第 1 个物品的体积要小于等于背包容量
            if (weight[0] <= j) {
                dp[0][j] = value[0];
            }
        }

        for (int i = 1; i < N; i++) {
            for (int j = 0; j <= V; j++) {
                dp[i][j] = dp[i - 1][j];
                if (weight[i] <= j) {
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - weight[i]] + value[i]);
                }
            }
        }

        // 输出
        System.out.println(dp[N - 1][V]);
    }
}

第 2 版:使用二维数组,设置「哨兵」行

Java 代码:

import java.util.Scanner;

public class Main {

    // 0-1 背包问题
    // 判题地址:https://www.acwing.com/problem/content/description/2/

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读第 1 行
        int N = scanner.nextInt();
        int V = scanner.nextInt();

        // 读后面的体积和价值
        int[] weight = new int[N];
        int[] value = new int[N];

        for (int i = 0; i < N; i++) {
            weight[i] = scanner.nextInt();
            value[i] = scanner.nextInt();
        }

        // 多开一行,避免对第 1 行单独赋值
        // 后面要注意下标,有下标 weight[i] 和 value[i] 的地方都要减 1
        int[][] dp = new int[N + 1][V + 1];

        for (int i = 1; i <= N; i++) {
            for (int j = 0; j <= V; j++) {
                dp[i][j] = dp[i - 1][j];
                if (weight[i - 1] <= j) {
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - weight[i - 1]] + value[i - 1]);
                }
            }
        }
        // 输出
        System.out.println(dp[N][V]);
    }
}

第 3 版:状态压缩,从后向前写,因为压缩了行,相当于设置了「哨兵」行

Java 代码:

import java.util.Scanner;

public class Main {

    // 0-1 背包问题
    // 判题地址:https://www.acwing.com/problem/content/description/2/

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读第 1 行
        int N = scanner.nextInt();
        int V = scanner.nextInt();

        // 读后面的体积和价值
        int[] weight = new int[N];
        int[] value = new int[N];

        for (int i = 0; i < N; i++) {
            weight[i] = scanner.nextInt();
            value[i] = scanner.nextInt();
        }

        // 状态压缩的写法:
        int[] dp = new int[V + 1];
        for (int i = 1; i <= N; i++) {
            for (int j = V; j >= weight[i - 1]; j--) {
                dp[j] = Math.max(dp[j], dp[j - weight[i - 1]] + value[i - 1]);
            }
        }

        // 输出
        System.out.println(dp[V]);
    }
}
发布了455 篇原创文章 · 获赞 348 · 访问量 126万+

猜你喜欢

转载自blog.csdn.net/lw_power/article/details/104974222
今日推荐