纯个人整理,蓝桥杯使用的算法模板day2(0-1背包问题),手打个人理解注释,超全面,且均已验证成功(附带详细手写“模拟流程图”,全网首个

算法索引

01背包

优化前

java 复制代码
    /**
     * 0-1背包问题解法(与下方代码表格示例对应,已模拟验证)
     * @param W 背包的总容量(示例:8)
     * @param weights 物品的重量数组(示例:[2, 3, 4, 5])
     * @param values 物品的价值数组(示例:[3, 4, 5, 6])
     * @param n 物品的总数量(示例:4)
     * @return 能够装入背包的最大价值
     */

public int[][] dp(int W, int[] weights, int[] values, int n){
	// 创建动态规划表,dp[i][w]表示前i个物品在容量为w时的最大价值
	int[][] dp = new int[n][W + 1];
	for(int j = weights[0]; j <= W; j++){ //初始化背包,物品数量为1时,背包容量满足时,价格始终为第一个物品价值(3)
		dp[0][j] = values[0];
	}
	for(int i = 1; i < n; i++){ //从第二个物品开始遍历
		for(int j = 0; j <= W; j++){ //遍历每种背包容量
			if(j >= weights[i]){ //当前遍历的物品可以放入背包,因为j(总背包容量)>= wt[i](当前物品重量)
			//选择放入或不放入物品,取价值的最大值
				dp[i][j] = Math.max(
					dp[i - 1][j], //不放入物品,所以(总背包价值)不变
					dp[i - 1][j - weights[i]] + values[i] //放入物品,1(dp[i - 1][j - weights[i]]).总背包容量减去wt[i](即j - wt[i])(当前物品重量),此时为剩余背包容量,再看剩余背包容量的"背包总价值";(例如,剩余背包容量的"背包总价值"为0,则直接添加当前物品的价值val[i],即下方代码示例表格的i=1,j=3(dp[1][3])的情况,剩余背包容量的"背包总价值"为dp[0][0],即剩余背包容量的"背包总价值"为0)2(+ values[i]).增加第i个物品的价值val[i](数组中即i)
				);
			}else{ //不可以放入背包
				dp[i][j] = dp[i - 1][j]; //不放入,即保持"同一背包容量下,放入上一个物品时的背包总价值"不变(且第一个物品的数值均已手动初始化,实现数据调用闭环)
			}
		}
	}

	return dp[n - 1][W]; //返回最后一个汇总的
}

空间优化版(使用一维数组)

java 复制代码
    /**
     * 0-1背包问题解法(已验证)
     * @param W 背包的总容量(示例:8)
     * @param weights 物品的重量数组(示例:[2, 3, 4, 5])
     * @param values 物品的价值数组(示例:[3, 4, 5, 6])
     * @param n 物品的总数量(示例:4)
     * @return 能够装入背包的最大价值
     */
public static int knapsackOptimized(int W, int[] weights, int[] values, int n) {
        // 使用一维数组代替二维数组,优化空间复杂度
        int[] dp = new int[W + 1];
        
        // 初始化:容量为0时价值为0
        dp[0] = 0;
        
        // 动态规划过程
        for (int i = 0; i < n; i++) { // 遍历每个物品
            // 必须逆向遍历背包容量,防止重复计算
            for (int j = W; j >= weights[i]; j--) {
                // 更新dp[w]的值
                dp[j] = Math.max(
                    dp[j], // 不选当前物品
                    dp[j - weights[i]] + values[i] // 选择当前物品
                );
             }
        }
        
        return dp[W]; // 返回最终结果
    }

优化后的模拟流程图

为何优化后,j不能使用正序遍历

java 复制代码
    /**
     * 0-1背包问题解法(已验证)
     * @param W 背包的总容量(示例:8)
     * @param weights 物品的重量数组(示例:[2, 3, 4, 5])
     * @param values 物品的价值数组(示例:[3, 4, 5, 6])
     * @param n 物品的总数量(示例:4)
     * @return 能够装入背包的最大价值
     */
public static int knapsackOptimized(int W, int[] weights, int[] values, int n) {
        // 使用一维数组代替二维数组,优化空间复杂度
        int[] dp = new int[W + 1];
        
        // 初始化:容量为0时价值为0
        dp[0] = 0;
        
        // 动态规划过程
        for (int i = 0; i < n; i++) { // 遍历每个物品
            // 必须逆向遍历背包容量,防止重复计算
            for (int j = 0; j >= weights[i]; j++) {
                // 更新dp[w]的值
                dp[j] = Math.max(
                    dp[j], // 不选当前物品
                    dp[j - weights[i]] + values[i] // 选择当前物品
                );
             }
        }
        
        return dp[W]; // 返回最终结果
    }
模拟流程图

代码对应实现案例

设定 w e i g h t s = [ 2 , 3 , 4 , 5 ] weights=[2,3,4,5] weights=[2,3,4,5], v a l u e s = [ 3 , 4 , 5 , 6 ] values = [3,4,5,6] values=[3,4,5,6]

横轴: j j j(总背包容量);纵轴: i i i(第 i i i个物品); d p dp dp单元格:总背包价值

i\j 0 1 2 3 4 5 6 7 8
0 0 0 3 3 3 3 3 3 3
1 0 0 3 4 4 7 7 7 7
2 0 0 3 4 5 7 8 9 9
3 0 0 3 4 5 7 8 9 10
相关推荐
焦耳加热1 小时前
阿德莱德大学Nat. Commun.:盐模板策略实现废弃塑料到单原子催化剂的高值转化,推动环境与能源催化应用
人工智能·算法·机器学习·能源·材料工程
wan5555cn1 小时前
多张图片生成视频模型技术深度解析
人工智能·笔记·深度学习·算法·音视频
u6062 小时前
常用排序算法核心知识点梳理
算法·排序
蒋星熠4 小时前
Flutter跨平台工程实践与原理透视:从渲染引擎到高质产物
开发语言·python·算法·flutter·设计模式·性能优化·硬件工程
小欣加油4 小时前
leetcode 面试题01.02判定是否互为字符重排
数据结构·c++·算法·leetcode·职场和发展
3Cloudream4 小时前
LeetCode 003. 无重复字符的最长子串 - 滑动窗口与哈希表详解
算法·leetcode·字符串·双指针·滑动窗口·哈希表·中等
王璐WL4 小时前
【c++】c++第一课:命名空间
数据结构·c++·算法
空白到白5 小时前
机器学习-聚类
人工智能·算法·机器学习·聚类
索迪迈科技5 小时前
java后端工程师进修ing(研一版 || day40)
java·开发语言·学习·算法
zzzsde5 小时前
【数据结构】队列
数据结构·算法