acwing_蓝桥杯 DP

88 阅读1分钟

01背包问题

思路
  • 二维: 状态表示 定义 f[i][j] 表示 在考虑 第 i 个物品选或不选,总体积不超过j的集合区间。 选取所有选法的最大值
  • 状态计算 : 不选 : f[i][j] = f[i -1] [j] 选 : f[i][j] = f[i - 1] [ j - v] + w;
  • 决策 取 最大值 :选择 不选和 选两种状态下的最大值即可。
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[] v = new int[n + 1];
        int[] w = new int[n + 1];
        for (int i = 1; i <= n ; i ++) {
            v[i] = sc.nextInt();
            w[i] = sc.nextInt();
        }
        int[][] f = new int[n + 1][ m + 1];
        
        for (int i = 1 ; i <= n ; i ++) {
            for (int j = 1 ; j <= m; j ++) {
                if (j < v[i]) f[i][j] = f[ i - 1][j];
                if (j >= v[i]) f[i][j] = Math.max(f[i - 1][j] , f[i - 1][j - v[i]] + w[i]);        
            }
        }
        
        System.out.println(f[n][m]);
    }
}

优化 为 一维dp

上面的状态计算 方程

不选 : f[i][j] = f[i -1] [j] 选 : f[i][j] = f[i - 1] [ j - v] + w;

i 状态都只与 i-1 这层状态相关。 可以用滚动数组进行优化。 不选 f[j] = f[j]

选 f[j] = f[j - v] + w;

为什么逆序 :保证上一层 v[i] 数据没有被污染 从后往前遍历。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[] v = new int[n + 1];
        int[] w = new int[n + 1];
        for (int i = 1; i <= n ; i ++) {
            v[i] = sc.nextInt();
            w[i] = sc.nextInt();
        }
        int[]f = new int[ m + 1];
        
        for (int i = 1 ; i <= n ; i ++) {
            for (int j = m ; j >= v[i]; j --) {
                 f[j] = Math.max(f[j] , f[j - v[i]] + w[i]);        
            }
        }
        
        System.out.println(f[m]);
    }
}