AHU 算法分析 实验四 动态规划

实验四:动态规划

实验目的

• 理解动态规划的基本思想,理解动态规划算法的两个基本要素最 优子结构性质和子问题的重叠性质。

• 熟练掌握典型的动态规划问题。

• 掌握动态规划思想分析问题的一般方法,对较简单的问题能正确 分析,设计出动态规划算法,并能快速编程实现。

钢条切割问题

有一段长度为n的钢条,钢条可以被分割成不同的长度的小钢 条出售,不同的小钢条对应不同的售价。详见下表:

钢条长度012345678910
价格p01589101717202424

钢条切割问题是这样的: 给定⼀段长度为n的钢条和⼀个价格表 pi(i=1,2,…n), 求切割钢条⽅案, 使得销售收益最⼤。 注意, 如果长度为n英⼨的钢条的价格pn⾜够⼤, 最优解可能就是完全不需 要切割。

输入:钢条的长度n,不同长度钢条的价值Pi,{i=1,…,n}

输入:1、最大收益,2、切割方案。

问题分析

我们选用一个状态方程去描述问题,设f(i,j)为状态方程,含义是在0~i种可被切割长度,j为当前钢条长度,举例f(3,5)意思就是在当前长度为5的时候,钢条可被切成0,1,2,3,这几种长度。

当我们不选择第i种切割方式时,那么还剩i-1种切割方式,所以有状态转移方程
f ( i , j ) = f ( i − 1 , j ) f( i,j)=f(i-1,j) f(i,j)=f(i1,j)
当我们选择第i种切割方式的时候,如果此时 i > j i>j i>j, 那么应该放弃这种方案,即状态转移方程为
f ( i , j ) = f ( i − 1 , j ) f(i,j)=f(i-1,j) f(i,j)=f(i1,j)
如果此时 i < = j i<=j i<=j, 因为这种方式可能被选择多次,所以我们选择k次来表示,以不失一般性,那么状态转移方程为
f ( i , j ) = m a x ( ∑ k = 0 + ∞ f ( i − 1 , j − k ∗ i ) + k ∗ a [ i ] ) f(i,j)=max(\sum_{k=0}^{+\infty}f(i-1,j-k*i)+k*a[i]) f(i,j)=max(k=0+f(i1,jki)+ka[i])
然后将选择第i种方案合并,即状态转移方程为
f ( i , j ) = m a x ( f ( i − 1 , j ) , ∑ k = 0 + ∞ f ( i − 1 , j − k ∗ i ) + k ∗ a [ i ] ) f(i,j)=max(f(i-1,j), \ \sum_{k=0}^{+\infty}f(i-1,j-k*i)+k*a[i]) f(i,j)=max(f(i1,j), k=0+f(i1,jki)+ka[i])
这里我们进行一个数学方程的变换
f ( i , j − i ) = m a x ( ∑ k = 0 + ∞ f ( i − 1 , j − ( k + 1 ) ∗ i ) + k ∗ a [ i ] ) f(i,j-i)=max(\sum_{k=0}^{+\infty}f(i-1,j-(k+1)*i)+k*a[i]) f(i,ji)=max(k=0+f(i1,j(k+1)i)+ka[i])
可以将两个式子联立
f ( i , j ) = m a x ( f ( i − 1 , j ) , f ( i , j − i ) + a [ i ] ) f(i,j)=max(f(i-1,j),\ f(i,j-i)+a[i]) f(i,j)=max(f(i1,j), f(i,ji)+a[i])
分析完毕

源代码

#include <iostream>
using namespace std;int a[1000];
int dp[1000][1000];
int x[1000];int fun(int len) {for (int i = 1; i <=len; i++) {for (int j = 0; j <=len; j++) {dp[i][j]=dp[i-1][j];if(j>=i)dp[i][j] = max(dp[i-1][j], dp[i][j - i] + a[i]);}}return dp[len][len];
}void traceback(int j, int y)
{while (j) {while (y < j) {j--;}if (dp[j][y] == (dp[j][y - j] + a[j]))                                  {x[j]++;y = y - j;++j;}j--;}
}
int main(){int len = 0;int sum = 0;bool flag=1;cin >> len;for (int i = 1; i <= len; i++) {scanf("%d", &a[i]);}cout << fun(len)<<endl;traceback(len, len);cout << "切割方案为:将长度为" << len << "的钢条切割成";for (int i = 1; i <= len; i++) {while (x[i]--) {cout << i << "  ";sum = sum + a[i];}}cout << "\n最大收益为" << sum;return 0;
}

然后可以优化代码,让空间复杂度减小一倍

int a[1000];
int dp[1000];
int x[1000];int fun(int len) {for (int i = 1; i <=len; i++) {for (int j =i; j <=len; j++) {dp[j] = max(dp[j], dp[j - i] + a[i]);}}return dp[len];
}void traceback(int j, int y)
{while (j) {while (y < j) {j--;}if (dp[y] == (dp[y - j] + a[j]))                                  {x[j]++;y = y - j;++j;}j--;}
}
int main(){int len = 0;int sum = 0;bool flag=1;cin >> len;for (int i = 1; i <= len; i++) {scanf("%d", &a[i]);}cout << fun(len)<<endl;traceback(len, len);cout << "切割方案为:将长度为" << len << "的钢条切割成";for (int i = 1; i <= len; i++) {while (x[i]--) {cout << i << "  ";sum = sum + a[i];}}cout << "\n最大收益为" << sum;return 0;
}

结果演示

在这里插入图片描述

实验总结

在写这个实验的时候,刚开始我使用了递归的方法,然后由于递归比较难回溯,所以改进算法,使用了动态规划,这道题我研究调试代码很长时间,虽然耗费很久,但是通过这次实验我对动态规划掌握更进一步,还是让我受益良多。当面对一些具有重叠子问题性质的问题时,动态规划(Dynamic Programming)是一种常用的解决方法。它通过将问题拆分为更小的子问题,并将子问题的解存储起来,避免了重复计算,从而提高算法的效率。动态规划的基本思想是利用已经计算过的子问题的解来计算更大规模的问题的解,这种思想被称为"最优子结构"。通过定义状态、状态转移方程和初始条件,我们可以构建动态规划算法。动态规划可以分为以下几个步骤:定义状态:明确问题需要求解的状态是什么,可以用一个或多个变量来表示。这些状态可以表示问题的规模、位置、限制条件等。确定状态转移方程:找到问题的递推关系,即将大规模问题的解表示为小规模问题的解。这需要根据问题的特点和已知信息建立数学模型。状态转移方程描述了问题从一个状态转移到另一个状态的方式。定义初始条件:确定最小规模的问题的解,即边界条件。这些初始条件可以是已知的问题解,或者根据问题的特点进行定义。使用迭代或递归的方式计算问题的解:根据状态转移方程,使用循环迭代或递归方式计算问题的解,并将中间结果保存起来,避免重复计算。输出结果:根据问题要求,输出最终求解得到的结果。动态规划在解决一些经典问题中非常有效,如背包问题、最长公共子序列问题、最短路径问题等。通过合理定义状态和状态转移方程,动态规划可以大大简化问题的求解过程,提高算法的效率。

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

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

相关文章

网络故障基本判断方法

1&#xff09;电脑上使用winR键&#xff0c;打开运行窗口&#xff0c;输入CMD命令&#xff0c;点击回车键 2&#xff09;在弹出的CMD运行窗口中输入ipconfig命令 通过该命令可以查看本机的IP地址&#xff0c;子网掩码和网关等信息。确认电脑中所有网卡配置是否正确。 3&…

llc稳压基本思路2

这套控制思路实际上就是开关电源中常见的反馈系统 大致思路就是&#xff0c;如果由于其他参数波动引起了输出电压偏差&#xff0c;我们可以直接监测这个输出电压&#xff0c;然后根据输出电压与目标电压值的偏差信号传输给芯片&#xff0c;然后芯片来改变频率&#xff0c;从而改…

人工智能研究的各个学派

于对智能产生根源的理解不同形成了三大学派。 一、符号主义 符号主义&#xff08;Symbolism&#xff09;是人工智能研究中的一个重要学派&#xff0c;也被称为逻辑主义&#xff08;Logicism&#xff09;、心理学派&#xff08;Psychlogism&#xff09;或计算机学派&#xff08…

Flink StreamTask启动和执行源码分析

文章目录 前言StreamTask 部署启动Task 线程启动StreamTask 初始化StreamTask 执行 前言 Flink的StreamTask的启动和执行是一个复杂的过程&#xff0c;涉及多个关键步骤。以下是StreamTask启动和执行的主要流程&#xff1a; 初始化&#xff1a;StreamTask的初始化阶段涉及多个…

蓝桥杯2023年-接龙数列(dp)

题目描述 对于一个长度为 K 的整数数列&#xff1a;A1, A2, . . . , AK&#xff0c;我们称之为接龙数列当且仅当 Ai 的首位数字恰好等于 Ai−1 的末位数字 (2 ≤ i ≤ K)。 例如 12, 23, 35, 56, 61, 11 是接龙数列&#xff1b;12, 23, 34, 56 不是接龙数列&#xff0c;因为 …

前端学习之行内和块级标签

行内标签 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>span</title> </head> <body><!-- 行内标签特点&#xff1a;1、不换行,一行可以放多个2、默认宽度内容撑开代表&#…

[2023年]-hadoop面试真题(一)

&#xff08;北京&#xff09;HDFS底层存储原理? (北京) HDFS读写数据流程? (北京) HDFS如何管理元数据或者checkpoint的理解 ? (北京) HDFS常用命令 ? (北京) hadoop调优 (北京) HDFS扩容原理 (北京) HDFS有哪些进程,分别是什么? (北京) HDFS中大量小文件对…

Go实现日志2——支持结构化和hook

代码保存在&#xff1a;https://github.com/liwook/Go-projects/tree/main/log/sulogV2​​​​​​​ 1.日志结构化 日志记录的事件以结构化格式(键值对&#xff0c;或通常是 JSON)表示&#xff0c;随后可以通过编程方式对其进行解析&#xff0c;便于对日志进行监控、警报、…

Googlenet网络架构

原文链接&#xff1a;[1409.4842v1] Going Deeper with Convolutions (arxiv.org) 图源&#xff1a;深入解读GoogLeNet网络结构&#xff08;附代码实现&#xff09;-CSDN博客 表截自原文 以下&#x1f4d2;来自博客深入解读GoogLeNet网络结构&#xff08;附代码实现&#xff0…

【顶刊|修正】多区域综合能源系统热网建模及系统运行优化【复现+延伸】

目录 主要内容 部分代码 结果一览 下载链接 主要内容 该程序复现《多区域综合能源系统热网建模及系统运行优化》模型并进一步延伸&#xff0c;基于传热学的基本原理建立了区域热网能量传输通用模型&#xff0c;对热网热损方程线性化实现热网能量流建模&#xff0…

使用docker-compose编排ruoyi项目

目录 一、开始部署 1.拉取ruoyi代码 2.拉取node镜像 3.拉取maven镜像 4.在/root/ruoyi/java下写一个Dockerfile用于后端Java环境 5.拉取MySQL&#xff0c;Redis&#xff0c;Nginx镜像 6.在/root/java目录下写一个nginx.conf 7.在/root/ruoyi目录下写docker-compose.yml文…

Idea导入Maven项目

方法一&#xff1a;使用Maven面板 方法二&#xff1a;在项目结构中设置&#xff0c;在最后一步中选择pom.xml。

js【详解】bind()、call()、apply()( 含手写 bind,手写 call,手写 apply )

必备知识点&#xff1a;js 【详解】函数中的 this 指向_js function this-CSDN博客 https://blog.csdn.net/weixin_41192489/article/details/123093256 bind、call、apply 的相同点 都是Function原型上的方法用途都是改变 this 的指向第一个参数都是新的 this bind、call、app…

前端学习之列表标签

目录 有序列表 结果 无序标签 结果 数据标签 结果 有序列表 &#xff08;注&#xff1a;注释是解释&#xff09; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Document</title> </…

SpringBoot实现 PDF 添加水印

方案一&#xff1a;使用 Apache PDFBox 库 ①、依赖 <dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.24</version> </dependency>②、添加水印 public class PdfoxWaterma…

蓝桥集训之日期差值

蓝桥集训之日期差值 模版&#xff1a;判断闰年 总天数 月份天数 #include <iostream>#include <cstring>#include <algorithm>using namespace std;const int months[]{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};int is_leap(int y){if(y % 10…

【JavaEE初阶系列】——计算机是如何工作的

目录 &#x1f388;冯诺依曼体系 ❗外存和内存的概念 ❗CPU中央处理器—人类当今科技领域巅峰之作之一 &#x1f6a9;如何衡量cpu &#x1f6a9;指令&#xff08;Instruction&#xff09; &#x1f388;操作系统&#xff08;Operating System&#xff09; &#x1f388;…

关于GPU显卡的介绍

一.关于英伟达历代产品架构 显卡是一种计算机硬件设备,也被称为显示适配器或图形处理器。目前的硬件部分主要由主板、芯片、存储器、散热器&#xff08;散热片、风扇&#xff09;等部分。显卡的主要芯片是显卡的主要处理单元。显卡上也有和计算机存储器相似的存储器&#xff0…

聊聊.NET中的连接池

在.NET中&#xff0c;连接池被广泛用于管理和优化不同类型资源的连接。连接池可以减少建立和关闭连接所需的时间和资源消耗&#xff0c;从而提高了应用程序的性能和响应能力。 HttpClient中的连接池 System.Net.Http.HttpClient 类用于发送 HTTP 请求以及从 URI 所标识的资源…

安全测试报告-模板内容

1. 概述 为检验XXXX平台 系统的安全性&#xff0c;于 XXXX年 XX 月 XX 日至 XXXX年 XX 月 XX日对目标系统进行了安全测试。在此期间测试人员将使用各 种非破坏性质的攻击手段&#xff0c;对目标系统做深入的探测分析&#xff0c;进而挖掘系统中的安 全漏洞和风险隐患。研发团队…