博客
关于我
完全背包问题的简化思路
阅读量:354 次
发布时间:2019-03-04

本文共 1851 字,大约阅读时间需要 6 分钟。

问题描述

我们需要解决一个典型的0-1背包问题:给定n个物品,每个物品都有一个重量wi和一个价值vi。我们的目标是从这些物品中选择一些,使得总重量不超过给定的容量W,同时使得所选物品的总价值最大化。

解决思路

传统的动态规划方法处理这个问题时,通常会采用以下策略:对于每个物品,我们可以选择拿取0、1、2、3...k个,然后剩余的容量中我们需要查询上一行对应的列,以找到最大的价值。然而,我们发现一个关键的优化点:对于当前物品,我们可以直接选择是否拿取它,而不是枚举所有可能的拿取次数。具体来说,我们可以这样处理:

  • 不拿取当前物品:此时的价值与上一行同一列的价值相同,即dp[i-1][j]
  • 拿取一个物品:此时,我们需要从当前行剩余的重量j-w[i]中选择最优的方案,并将当前物品的价值v[i]加到上述方案的价值上,即v[i] + dp[i][j-w[i]]
  • 这种方法的核心在于,当我们拿取一个物品后,剩余的重量可以继续使用同一行的动态规划结果,这样可以避免重复计算多次循环,显著降低时间复杂度。

    具体代码

    import java.util.Scanner;import static java.lang.Math.max;public class Main {    public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        int n = sc.nextInt();        int w[] = new int[n];        int v[] = new int[n];        for (int i = 0; i < n; i++) {            w[i] = sc.nextInt();        }        for (int i = 0; i < n; i++) {            v[i] = sc.nextInt();        }        int W = sc.nextInt();        int res = solution(w, v, n, W);        System.out.println(res);        sc.close();    }    private static int solution(int[] w, int[] v, int n, int W) {        int[][] dp = new int[n][W + 1];        // 初始化第一行与第一列        for (int i = 0; i <= W; i++) {            dp[0][i] = i / w[0] * v[0];        }        for (int i = 1; i < n; i++) {            for (int j = 1; j <= W; j++) {                if (j >= w[i]) {                    dp[i][j] = max(dp[i-1][j], v[i] + dp[i][j - w[i]]);                } else {                    dp[i][j] = dp[i-1][j];                }            }        }        return dp[n-1][W];    }}

    代码解释

  • 输入处理:读取物品数量n,然后依次读取每个物品的重量和价值,最后读取总容量W。
  • 动态规划数组初始化:创建一个二维数组dp,其中dp[i][j]表示处理前i个物品且总重量为j时的最大价值。
  • 初始化第一行:处理第一个物品时,只能选择拿取0个或多个。因此,dp[0][i] = i / w[0] * v[0],即每个i的价值由第一个物品的价值决定。
  • 填充动态规划表:对于每个物品i和每个重量j,判断是否可以拿取当前物品。如果可以,比较不拿取和拿取当前物品两种情况,选择较大的那个值;否则,直接采用上一行的结果。
  • 返回结果:最终返回处理完所有物品且总重量不超过W时的最大价值。
  • 这种方法通过合理简化循环结构,避免了传统动态规划中的重复计算,显著提升了算法的效率。

    转载地址:http://btwg.baihongyu.com/

    你可能感兴趣的文章
    Scala集合-数组、元组
    查看>>
    Flink Standalone集群安装和部署
    查看>>
    JAVA网络爬虫01-http client爬取网络内容
    查看>>
    04 程序流程控制
    查看>>
    java并发编程(1)
    查看>>
    C++&&STL
    查看>>
    双指针算法思想
    查看>>
    分组背包问题
    查看>>
    子集(LeetCode 78)
    查看>>
    重建二叉树
    查看>>
    旋转数组的最小值
    查看>>
    1089 狼人杀-简单版
    查看>>
    1004 Counting Leaves (30分)
    查看>>
    1093 Count PAT‘s (25分) 含DP做法
    查看>>
    四平方和
    查看>>
    最大序列和
    查看>>
    一篇解决JMM与volatile详解(二)
    查看>>
    数据结构之数组与经典面试题(二)
    查看>>
    无锁并发框架-Disruptor的使用(二)
    查看>>
    Android wm命令
    查看>>