【潜意识Java】蓝桥杯算法有关的动态规划求解背包问题

简介: 本文介绍了经典的0/1背包问题及其动态规划解法。

 目录

背包问题简介

问题描述

输入:

输出:

动态规划解法

动态规划状态转移

代码实现

代码解释

动态规划的时间复杂度

例子解析

输出:

总结


作者我蓝桥杯:2023第十四届蓝桥杯国赛C/C++大学B组一等奖,所以请听我讲:

image.gif 编辑

蓝桥杯是一项备受推崇的编程比赛,参赛者需要通过高效的算法解决各种具有挑战性的问题。今天,我们将深入探讨蓝桥杯经典算法题目之一——0/1背包问题。通过这个题目,我们不仅可以学习如何高效使用动态规划,还能够更好地掌握如何在实际问题中应用算法思想。

背包问题简介

🍎背包问题的核心思想是:给定一组物品,每个物品有一个重量和一个价值,现在有一个背包,背包的容量有限,问如何选择物品放入背包,使得在不超过背包容量的情况下,物品的总价值最大。🍊

应该也很要理解,就是这么个道理:

🍏在0/1背包问题中,每个物品只能选择放入背包一次,要么放入背包,要么不放入。🍏

image.gif 编辑

image.gif 编辑

问题描述

那我们假设我们有一个背包,他的容量为C,有n个物品。其中每个物品有一个重量wi和一个价值vi。我们需要在这些物品中选择若干个物品放入背包,使得背包中物品的总价值最大,并且物品的总重量不超过背包的容量。就是这个问题。

输入:

  • 第1行:nC,表示物品的数量和背包的容量。
  • 第2至n+1行:每行包含两个整数wivi,分别表示第i个物品的重量和价值。

输出:

  • 输出一个整数,表示在不超过背包容量的前提下,能够获得的最大价值。

动态规划解法

是一种通过将复杂问题分解成子问题来求解的方法。在背包问题中,我们可以定义一个二维数组dp[i][j],表示前i个物品中能够在容量为j的背包中获得的最大价值。

image.gif 编辑

动态规划状态转移

  • 如果第i个物品不放入背包,那么dp[i][j] = dp[i-1][j],即最大价值与不放入这个物品时的最大价值相同。🥞🥞🥞🥞
  • 如果第i个物品放入背包,那么dp[i][j] = dp[i-1][j-wi] + vi,即最大价值为放入该物品后,剩余容量所能获得的最大价值。🍔🍔🍔🍔🍔

最终,我们要求解的是dp[n][C],即在n个物品和背包容量C下,能够获得的最大价值。

代码实现

import java.util.Scanner;
public class Knapsack {
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        // 输入物品数量和背包容量
        int n = sc.nextInt();
        int C = sc.nextInt();
        
        // 定义物品的重量和价值
        int[] weight = new int[n + 1];
        int[] value = new int[n + 1];
        
        // 输入每个物品的重量和价值
        for (int i = 1; i <= n; i++) {
            weight[i] = sc.nextInt();
            value[i] = sc.nextInt();
        }
        // dp数组,dp[i][j]表示前i个物品,背包容量为j时的最大价值
        int[][] dp = new int[n + 1][C + 1];
        
        // 动态规划求解
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j <= C; j++) {
                if (j >= weight[i]) {
                    // 如果当前物品可以放入背包,则选择放与不放的最大值
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
                } else {
                    // 当前物品不能放入背包时,最大价值与不放当前物品时相同
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        // 输出最大价值
        System.out.println(dp[n][C]);
        sc.close();
    }
}

image.gif

代码解释

  1. 输入处理:首先通过Scanner读取物品数量n和背包容量C,然后通过循环输入每个物品的重量和价值。
  2. DP数组:使用一个二维数组dp[i][j]表示在前i个物品和容量为j的背包中能获得的最大价值。
  3. 状态转移:遍历每个物品,对于每种可能的背包容量j,根据是否将当前物品放入背包,更新dp[i][j]
  4. 输出:最后输出dp[n][C],即在所有物品和背包容量下能够获得的最大价值。

都挺难的,大家好好消化吧,到时候更新更加详细的教程,方便大家理解。

动态规划的时间复杂度

该算法的时间复杂度是O(n * C),其中n是物品的数量,C是背包的容量。空间复杂度也是O(n * C),主要由dp数组占据。

例子解析

假设有如下输入:

4 5 2 3 3 4 4 5 5 6

这意味着有4个物品,背包容量为5,物品的重量和价值分别为:

物品 重量 价值
1 2 3
2 3 4
3 4 5
4 5 6

使用动态规划的算法,我们可以求得最大价值为7,即选择物品1(重量2,价值3)和物品2(重量3,价值4)放入背包中,背包容量为5,总价值为7。

输出:

7

image.gif 编辑

image.gif 编辑


相关文章
|
7天前
|
存储 算法 Java
解锁“分享文件”高效密码:探秘 Java 二叉搜索树算法
在信息爆炸的时代,文件分享至关重要。二叉搜索树(BST)以其高效的查找性能,为文件分享优化提供了新路径。本文聚焦Java环境下BST的应用,介绍其基础结构、实现示例及进阶优化。BST通过有序节点快速定位文件,结合自平衡树、多线程和权限管理,大幅提升文件分享效率与安全性。代码示例展示了文件插入与查找的基本操作,适用于大规模并发场景,确保分享过程流畅高效。掌握BST算法,助力文件分享创新发展。
|
24天前
|
存储 Java 开发者
【潜意识Java】深入详细理解分析Java中的toString()方法重写完整笔记总结,超级详细。
本文详细介绍了 Java 中 `toString()` 方法的重写技巧及其重要
46 10
【潜意识Java】深入详细理解分析Java中的toString()方法重写完整笔记总结,超级详细。
|
20天前
|
存储 人工智能 算法
解锁分布式文件分享的 Java 一致性哈希算法密码
在数字化时代,文件分享成为信息传播与协同办公的关键环节。本文深入探讨基于Java的一致性哈希算法,该算法通过引入虚拟节点和环形哈希空间,解决了传统哈希算法在分布式存储中的“哈希雪崩”问题,确保文件分配稳定高效。文章还展示了Java实现代码,并展望了其在未来文件分享技术中的应用前景,如结合AI优化节点布局和区块链增强数据安全。
|
21天前
|
算法 安全 Java
Java线程调度揭秘:从算法到策略,让你面试稳赢!
在社招面试中,关于线程调度和同步的相关问题常常让人感到棘手。今天,我们将深入解析Java中的线程调度算法、调度策略,探讨线程调度器、时间分片的工作原理,并带你了解常见的线程同步方法。让我们一起破解这些面试难题,提升你的Java并发编程技能!
59 16
|
24天前
|
算法 搜索推荐 Java
【潜意识Java】深度解析黑马项目《苍穹外卖》与蓝桥杯算法的结合问题
本文探讨了如何将算法学习与实际项目相结合,以提升编程竞赛中的解题能力。通过《苍穹外卖》项目,介绍了订单配送路径规划(基于动态规划解决旅行商问题)和商品推荐系统(基于贪心算法)。这些实例不仅展示了算法在实际业务中的应用,还帮助读者更好地准备蓝桥杯等编程竞赛。结合具体代码实现和解析,文章详细说明了如何运用算法优化项目功能,提高解决问题的能力。
55 6
|
1天前
|
安全 Java 程序员
Java 面试必问!线程构造方法和静态块的执行线程到底是谁?
大家好,我是小米。今天聊聊Java多线程面试题:线程类的构造方法和静态块是由哪个线程调用的?构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节有助于掌握Java多线程机制。下期再见! 简介: 本文通过一个常见的Java多线程面试题,详细讲解了线程类的构造方法和静态块是由哪个线程调用的。构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节对掌握Java多线程编程至关重要。
27 13
|
2天前
|
安全 Java 开发者
【JAVA】封装多线程原理
Java 中的多线程封装旨在简化使用、提高安全性和增强可维护性。通过抽象和隐藏底层细节,提供简洁接口。常见封装方式包括基于 Runnable 和 Callable 接口的任务封装,以及线程池的封装。Runnable 适用于无返回值任务,Callable 支持有返回值任务。线程池(如 ExecutorService)则用于管理和复用线程,减少性能开销。示例代码展示了如何实现这些封装,使多线程编程更加高效和安全。
|
1月前
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
100 17
|
2月前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者

热门文章

最新文章