【算法】动态规划

文章目录

  • 概述
  • 背包问题
    • 01背包问题:
    • 代码示例
    • 部分背包
      • 代码示例
    • 完全背包
      • 代码示例
    • 多重背包
      • 代码示例
  • 总结提升

概述

动态规划(Dynamic Programming)是一种通过将问题划分为相互重叠的子问题来解决问题的算法思想。其核心思想是通过保存已经计算过的子问题的解,避免重复计算,从而降低时间复杂度。

动态规划的适用条件包括:

问题具有最优子结构:问题的最优解可以通过子问题的最优解来构造。
子问题之间存在重叠:原问题的求解过程中,多次求解相同的子问题。
动态规划的基本步骤如下:

1、定义状态:明确问题的状态,并用状态变量表示。
2、确定状态转移方程:根据问题的最优子结构,确定状态之间的转移关系。
3、初始化:设置初始状态的值。
4、递推计算:根据状态转移方程,从初始状态逐步计算到目标状态。
5、求解目标:根据最终状态的值,得到问题的解。

背包问题

背包问题是一个经典的组合优化问题,在计算机科学和运筹学中具有广泛的应用。它的基本形式是:给定一个固定大小的背包,和一组物品,每个物品有对应的重量和价值。目标是在不超过背包容量的前提下,选择合适的物品放入背包,使得背包中物品的总价值最大化。

背包问题可以分为多个不同的变体,其中最常见的有01背包问题、部分背包、完全背包问题和多重背包问题。

01背包问题:

每个物品要么放入背包,要么不放入背包,不能拆分。
对于每个物品,只有两种选择,放入或者不放入背包。

代码示例

public class Knapsack {public static int knapsack(int[] weights, int[] values, int capacity) {int n = weights.length; // 物品个数int[][] dp = new int[n + 1][capacity + 1]; // 创建动态规划表for (int i = 1; i <= n; i++) {for (int j = 1; j <= capacity; j++) {if (weights[i - 1] > j) {dp[i][j] = dp[i - 1][j];} else {dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1]);}}}return dp[n][capacity];}public static void main(String[] args) {int[] weights = {2, 3, 4, 5}; // 物品重量int[] values = {3, 4, 5, 6};  // 物品价值int capacity = 8;            // 背包容量int max_value = knapsack(weights, values, capacity);System.out.println("最大价值: " + max_value);}
}

这段代码实现了 01 背包问题的动态规划解法。knapsack 方法接受物品重量数组 weights、物品价值数组 values 和背包容量 capacity 作为输入,并返回最大的背包价值。

代码中创建了一个二维数组 dp 来存储子问题的最优解。通过两层循环遍历每个子问题,并根据状态转移方程更新 dp 数组。最后,返回 dp[n][capacity],即表示最大的背包价值。

在上述示例中,测试样例中的物品重量为 [2, 3, 4, 5],物品价值为 [3, 4, 5, 6],背包容量为 8。输出结果为最大价值为 11。

部分背包

部分背包问题是一个在给定背包容量的限制下,选择物品放入背包以使得背包的总价值最大化的问题。与 0-1 背包问题不同的是,部分背包问题允许将物品分割成小块,并且可以选择装入一部分物品。

在部分背包问题中,每个物品都有一个重量和一个价值。目标是选择一些物品装入背包,使得被选中物品的总重量不超过背包的容量,同时使得它们的总价值最大化。

为了解决这个问题,我们可以根据物品的单位价值(即每单位重量的价值)进行排序,然后按照从高到低的顺序依次装入物品,直到背包无法再装入完整的物品为止。如果背包仍有剩余容量,则根据物品的单位价值将其分割成部分,并将部分装入背包,使得装入的部分物品价值最大化。

部分背包问题可以使用贪心算法来求解。通过按照单位价值排序并可根据限制条件逐步装入物品,贪心算法能够在较短的时间内得到一个近似最优解。

需要注意的是,部分背包问题的贪心算法并不一定能够得到最优解。在某些情况下,贪心选择可能会导致次优解或者错误的结果。因此,对于严格要求最优解的问题,可能需要使用其他算法来求解,如动态规划等。

代码示例

public class FractionalKnapsack {public static double fractionalKnapsack(int[] weights, int[] values, int capacity) {int n = weights.length;double[][] dp = new double[n + 1][capacity + 1];for (int i = 1; i <= n; i++) {int weight = weights[i - 1];int value = values[i - 1];for (int j = 1; j <= capacity; j++) {if (weight <= j) {// 可以完整装入当前物品dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight] + value);} else {// 只能装入一部分当前物品dp[i][j] = dp[i - 1][j];}}}return dp[n][capacity];}public static void main(String[] args) {int[] weights = {2, 3, 4, 5};int[] values = {3, 4, 5, 6};int capacity = 8;double max_value = fractionalKnapsack(weights, values, capacity);System.out.println("最大总价值: " + max_value);}
}

这段代码使用动态规划算法解决部分背包问题。weights 数组存储物品的重量,values 数组存储物品的价值,capacity 表示背包的容量。

通过创建一个二维数组 dp,其中 dp[i][j] 表示在考虑前 i 个物品,并且背包容量为 j 时的最大总价值。

代码中,使用两层循环遍历所有物品和背包容量的组合。对于每个物品,分为两种情况进行处理:

如果当前物品的重量小于等于背包容量,可以选择完整装入该物品。此时,最大总价值等于不装入该物品时的最大总价值 dp[i-1][j] 和装入该物品后的总价值 dp[i-1][j-weight] + value 中的较大值。
如果当前物品的重量大于背包容量,无法完整装入该物品。此时,最大总价值与上一个物品时的价值相同,即 dp[i][j] = dp[i-1][j]。
最后,返回二维数组 dp 中最后一个元素的值,即表示在考虑所有物品时,背包可以装入的最大总价值。

在上述示例中,测试样例中的物品数组包含四个物品,每个物品的重量和价值分别为 2、3、4、5 和 3、4、5、6,背包容量为 8。输出结果为最大总价值为 11.0。

完全背包

完全背包问题是一个在给定背包容量的限制下,选择物品放入背包以使得背包的总价值最大化的问题。与 0-1 背包问题和部分背包问题不同的是,完全背包问题允许将物品无限次地装入背包中。

在完全背包问题中,每个物品都有一个重量和一个价值。与部分背包问题类似,目标是选择一些物品装入背包,使得被选中物品的总重量不超过背包的容量,同时使得它们的总价值最大化。

为了解决这个问题,我们可以使用动态规划算法。通过创建一个二维数组 dp,其中 dp[i][j] 表示在考虑前 i 个物品,并且背包容量为 j 时的最大总价值。

与部分背包问题不同的是,在完全背包问题中,对于每个物品,我们可以选择装入 0 个、1 个、2 个,… 直到 j/weight[i] 个(j/weight[i] 向下取整)个物品。

因此,对于每个物品 i,我们可以使用以下递推关系来计算 dp[i][j]:

dp[i][j] = max(dp[i-1][j-k*weight[i]] + k*value[i]),其中 0 <= k <= j/weight[i]

遍历所有物品和背包容量的组合,通过上述递推关系更新 dp 数组中的值。

最后,返回二维数组 dp 中最后一个元素的值,即表示在考虑所有物品时,背包可以装入的最大总价值。

需要注意的是,完全背包问题的动态规划解法时间复杂度较高,并且可能需要大量的内存空间。为了提高效率,我们可以使用一维数组进行优化,在遍历物品时从小到大的顺序更新 dp 数组。

代码示例

public class CompleteKnapsack {public static int completeKnapsack(int[] weights, int[] values, int capacity) {int n = weights.length;int[] dp = new int[capacity + 1];for (int i = 0; i < n; i++) {int weight = weights[i];int value = values[i];for (int j = weight; j <= capacity; j++) {dp[j] = Math.max(dp[j], dp[j - weight] + value);}}return dp[capacity];}public static void main(String[] args) {int[] weights = {2, 3, 4, 5};int[] values = {3, 4, 5, 6};int capacity = 8;int max_value = completeKnapsack(weights, values, capacity);System.out.println("最大总价值: " + max_value);}
}

这段代码使用动态规划算法解决完全背包问题。weights 数组存储物品的重量,values 数组存储物品的价值,capacity 表示背包的容量。

通过创建一个一维数组 dp,其中 dp[j] 表示在考虑前所有物品,并且背包容量为 j 时的最大总价值。

代码中,首先遍历所有物品,然后遍历所有可能的容量,对于每个容量 j,计算出背包可以装入的最大总价值。

递推公式为:

dp[j] = max(dp[j], dp[j - weight] + value)

其中,weights[i] 表示第 i 个物品的重量,values[i] 表示第 i 个物品的价值。

在更新 dp[j] 的值时,我们将 dp[j-weight]+value 的值与 dp[j] 的值比较,取两者中的最大值作为新的 dp[j] 值。

最后,返回一维数组 dp 中最后一个元素的值,即表示在考虑所有物品时,背包可以装入的最大总价值。

在上述示例中,测试样例中的物品数组包含四个物品,每个物品的重量和价值分别为 2、3、4、5 和 3、4、5、6,背包容量为 8。输出结果为最大总价值为 18。

多重背包

多重背包问题是在给定背包容量的限制下,选择物品放入背包以使得背包的总价值最大化的问题。与完全背包问题类似,多重背包问题允许将某些物品选择多次放入背包中,但是每个物品的选择次数是有限制的。

在多重背包问题中,每个物品都有一个重量、价值和一个数量限制。目标是选择一些物品放入背包,使得被选中物品的总重量不超过背包的容量,同时使得它们的总价值最大化。

为了解决多重背包问题,我们可以使用动态规划算法。通过创建一个二维数组 dp,其中 dp[i][j] 表示在考虑前 i 个物品,并且背包容量为 j 时的最大总价值。

与完全背包问题类似,对于每个物品 i,我们需要考虑选择物品 i 的次数。假设该物品的选择次数上限为 k,则选择次数的范围是 0 到 min(k, j/weight[i])。

因此,对于每个物品 i,我们可以使用以下递推关系来计算 dp[i][j]:

dp[i][j] = max(dp[i-1][j-k*weight[i]] + k*value[i]),其中 0 <= k <= min(k, j/weight[i])

遍历所有物品和背包容量的组合,通过上述递推关系更新 dp 数组中的值。

最后,返回二维数组 dp 中最后一个元素的值,即表示在考虑所有物品时,背包可以装入的最大总价值。

需要注意的是,多重背包问题的动态规划解法时间复杂度较高,并且可能需要大量的内存空间。为了提高效率,我们可以使用一维数组进行优化,在遍历物品时从大到小的顺序更新 dp 数组。

代码示例

public class MultipleKnapsack {public static int multipleKnapsack(int[] weights, int[] values, int[] counts, int capacity) {int n = weights.length;int[] dp = new int[capacity + 1];for (int i = 0; i < n; i++) {int weight = weights[i];int value = values[i];int count = counts[i];for (int j = capacity; j >= weight; j--) {for (int k = 1; k <= count && k * weight <= j; k++) {dp[j] = Math.max(dp[j], dp[j - k * weight] + k * value);}}}return dp[capacity];}public static void main(String[] args) {int[] weights = {2, 3, 4};int[] values = {3, 4, 5};int[] counts = {2, 3, 1};int capacity = 8;int max_value = multipleKnapsack(weights, values, counts, capacity);System.out.println("最大总价值: " + max_value);}
}

这段代码使用动态规划算法解决多重背包问题。weights 数组存储物品的重量,values 数组存储物品的价值,counts 数组存储每个物品的数量限制,capacity 表示背包的容量。

通过创建一个一维数组 dp,其中 dp[j] 表示在考虑前所有物品,并且背包容量为 j 时的最大总价值。

代码中,首先遍历所有物品,然后通过两层循环遍历背包容量和物品的选择次数。对于每个物品,计算出选择不同次数情况下的最大总价值。

递推公式为:

dp[j] = max(dp[j], dp[j-k*weight]+k*value),其中 1 <= k <= min(count, j/weight)

在更新 dp[j] 的值时,我们将 dp[j-kweight]+kvalue 的值与 dp[j] 的值比较,取两者中的最大值作为新的 dp[j] 值。

最后,返回一维数组 dp 中最后一个元素的值,即表示在考虑所有物品时,背包可以装入的最大总价值。

在上述示例中,测试样例中的物品数组包含三个物品,每个物品的重量和价值分别为 2、3、4 和 3、4、5,数量限制分别为 2、3、1,背包容量为 8。输出结果为最大总价值为 20。

总结提升

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/145786.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

四、2023.9.30.C++面向对象end.4

文章目录 49、 简述一下什么是常函数&#xff0c;有什么作用&#xff1f;50、 说说什么是虚继承&#xff0c;解决什么问题&#xff0c;如何实现&#xff1f;51、简述一下虚函数和纯虚函数&#xff0c;以及实现原理&#xff1f;52、说说纯虚函数能实例化吗&#xff0c;为什么&am…

华为云云耀云服务器L实例评测|Ubuntu系统MySQL 8.1.0 Innovation压测

文章目录 前言&#x1f4e3; 1.前言概述&#x1f4e3; 2.云服务器性能监控&#x1f4e3; 3.MySQL8.1版本安装✨ 3.1 安装包下载✨ 3.2 解压安装包✨ 3.3 登录验证 &#x1f4e3; 4.ubuntu安装sysbench&#x1f4e3; 5.云服务器压测✨ 5.1 IO测试✨ 5.2 CPU性能测试 &#x1f4e…

uniapp 实现下拉筛选框 二次开发定制

前言 最近又收到了一个需求&#xff0c;需要在uniapp 小程序上做一个下拉筛选框&#xff0c;然后找了一下插件市场&#xff0c;确实有找到&#xff0c;但不过他不支持搜索&#xff0c;于是乎&#xff0c;我就自动动手&#xff0c;进行了二开定制&#xff0c;站在巨人的肩膀上&…

番外3:下载+安装VMware(前期准备)

step1: 查看自己笔记本电脑配置&#xff1b; step2: 下载并安装VMware&#xff08;下载地址www..kkx.net/soft/16841.html&#xff09;这里选择本地普通下载&#xff1b; step3: 安装VMware过程中需要填写密钥&#xff08;本人用的最后一个&#xff09;; #UU54R-FVD91-488PP-7N…

【农业生产模拟】WOFOST模型与PCSE模型实践

查看原文>>>【农业生产模拟】WOFOST模型与PCSE模型实践 WOFOST&#xff08;WorldFoodStudies&#xff09;和PCSE&#xff08;PythonCropSimulationEnvironment&#xff09;是两个用于农业生产模拟的模型&#xff1a;WOFOST是一个经过多年开发和验证的模型&#xff0c…

CFS内网穿透靶场实战

一、简介 不久前做过的靶场。 通过复现CFS三层穿透靶场&#xff0c;让我对漏洞的利用&#xff0c;各种工具的使用以及横向穿透技术有了更深的理解。 一开始nmap探测ip端口,直接用thinkphpv5版本漏洞工具反弹shell&#xff0c;接着利用蚁剑对服务器直接进行控制&#xff0c;留下…

使用Visual Studio调试排查Windows系统程序audiodg.exe频繁弹出报错

VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&#xff09;https://blog.csdn.net/chenlycly/article/details/124272585C软件异常排查从入门到精通系列教程&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&a…

为什么字节大量用GO而不是Java?

见字如面&#xff0c;我是军哥。 我看很多程序员对字节编程语言选型很好奇&#xff0c;为此我还特地问了在字节的两位4-1的技术大佬朋友&#xff0c;然后加上自己的思考&#xff0c;总结了一下就以下 2 个原因&#xff1a; 1、 选型上没有历史包袱 字节的早期的程序员大多来自于…

go字符串拼接方式及性能比拼

在golang中字符串的拼接方式有多种&#xff0c;本文将会介绍比较常用的几种方式&#xff0c;并且对各种方式进行压测&#xff0c;以此来得到在不同场景下更适合使用的方案。 文章目录 1、go字符串的几种拼接方式1.1 fmt.Sprintf1.2 运算符拼接1.3 strings.Join1.4 strings.Bui…

LaTex的学习(学习于b站西北农林科技大学耿楠教授的教学视频)

目录 一、LaTeX软件的安装与环境配置  1.LaTeX软件texlive的下载  2. texlive的安装 二、用命令行实现LaTeX文档的编写  1.通过命令行演示LaTeX编写的过程  2.将编译LaTeX并生成pdf文件的过程封装成一个bat文件  3.演示一个含有中文的LaTeX文件 三、用TexStudio IDE实…

回归预测 | MATLAB实现RUN-XGBoost龙格库塔优化极限梯度提升树多输入回归预测

回归预测 | MATLAB实现RUN-XGBoost多输入回归预测 目录 回归预测 | MATLAB实现RUN-XGBoost多输入回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现RUN-XGBoost多输入回归预测&#xff08;完整源码和数据&#xff09; 1.龙格库塔优化XGBoost&#xff0c;…

【Redis】redis基本数据类型详解(String、List、Hash、Set、ZSet)

目录 RedisString(字符串)List(列表)Hash(字典)Set(集合)ZSet(有序集合) Redis Redis有5种基本的数据结构&#xff0c;分别为&#xff1a;string&#xff08;字符串&#xff09;、list&#xff08;列表&#xff09;、set&#xff08;集合&#xff09;、hash&#xff08;哈希&a…

ahk系列——ahk_v2实现win10任意界面ocr

前言&#xff1a; 不依赖外部api接口&#xff0c;界面简洁&#xff0c;翻译快速&#xff0c;操作简单&#xff0c; 有网络就能用 、还可以把ocr结果非中文翻译成中文、同样可以识别中英日韩等60多个国家语言并翻译成中文&#xff0c;十分的nice 1、所需环境 windows10及其以上…

Linux学习记录——삼십일 socket编程---TCP套接字

文章目录 TCP套接字简单通信1、服务端1、基本框架2、获取连接 2、客户端3、多进程4、多线程5、线程池6、简单的日志系统7、守护进程8、其它 TCP套接字简单通信 本篇gitee 学习完udp套接字通信后&#xff0c;再来看TCP套接字。 四个文件tcp_server.hpp&#xff0c; tcp_serve…

Linux常见操作命令(1)

​ 前言&#xff1a;作者也是初学Linux&#xff0c;可能总结的还不是很到位 ♈️今日夜电波&#xff1a;达尔文—林俊杰 0:30━━━━━━️&#x1f49f;──────── 4:06 &#x1f504; ◀️ …

Redis与分布式-分布式锁

接上文 Redis与分布式-集群搭建 1.分布式锁 为了解决上述问题&#xff0c;可以利用分布式锁来实现。 重新复制一份redis&#xff0c;配置文件都是刚下载时候的不用更改&#xff0c;然后启动redis服务和redis客户。 redis存在这样的命令&#xff1a;和set命令差不多&#xff0…

Windows上安装 Go 环境

一、下载go环境 下载go环境&#xff1a;Go下载官网链接找到自己想下载的版本&#xff0c;点击下载&#xff0c;比如我这是windows64位的&#xff0c;我就直接点击最新的。 二、安装go环境 双击下载的.msi文件 next next 他默认的是c盘&#xff0c;你自己可以改&#xff0c;然…

Redis优化

Redis优化 一、Sring数据类型1.1、 概述1.2、 set/get/append/strlen命令1.3、 incr/decr/incrby/decrby 命令1.4、 getset命令1.5、 setex命令1.6、 setnx命令1.7、 mset/mget/msetnx命令 二、List数据类型2.1、 概述2.2、 lpush/lpushx/lrange命令2.3、 lpop/llen命令2.4、 l…

phpstudy_pro高效率建一个属于自己的网站

1.下载phpStudy_32 2.下载wordpress-6.3-zh_CN 安装好phpstudy后启动phpstudy中对应的服务&#xff0c;并在网站中配置好对一个的应用的路径 ps:根目录中的路径是你想要通过phpstudy部署应用的路径 这里以wordpress为例 将下载wordpress的压缩包解压后&#xff0c;需要修改…

VS+Qt+C++ GDAL读取tif图像数据显示

程序示例精选 VSQtC GDAL读取tif图像数据显示 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《VSQtC GDAL读取tif图像数据显示》编写代码&#xff0c;代码整洁&#xff0c;规则&#xff0c;…