【DP1】钢条分割详解

本文通过钢条切割问题介绍动态规划(DP)的概念。从递归解法开始,探讨如何优化成带备忘录的递归以及自底向上的迭代解法,强调了DP中的最优子结构、重叠子问题和无后效性这三个关键点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[DP]
原文再续书接上一回,上一篇文章的背包讲的有点过于狭隘,我就某一类问题解释一种算法的思想:动态规划(Dynamic Programming)。简称DP。
我们在生活中不免会遇到一类问题,求什么什么的最大,什么什么的最小。在这类问题中,如果有算法基础的同学可能会知道贪心算法。按个人理解,贪心算法就是DP算法中的一类。
那么DP是什么?我们直接用一道题目来举例子去解释DP。
这里采用的例子引用自CLRS中的钢条分割问题。我只做一个概括性复述。有兴趣的同学可以去看看原著(这里强力吹一波CLRS,如果能够静下心来看,这本书还是相当的不错。
长度为n英寸的钢条,若给出一个数组p[n],该数组是指不同长度下钢条所能给出的价格,例如:
在这里插入图片描述
有一种很蠢但是很好理解的算法,就是我一共有n个元素(长度为n的钢条分割最小单元为1的情况下,我最多有n个元素)。所以我一共有2^(n-1)个方案(含重复的)我每个方案都算一个价格出来,在其中取最大值不就可以了吗?
当然可以,但是开销也是蹭蹭蹭地往上跑。

我们先提出一种递归的解法。
我们来分析最初的情况,我们从最左端开始看
我们在一开始,在i=1的情况下,我们可以选择切/不切,我们也能推广到一般条件,当i=k时候切还是不切。
如图:

在这里插入图片描述
那么我们只需要外层嵌套一次for循环,我们有长度为N的一段钢条,那么只切一刀的情况下,我们一共有n-1种切法;切割完之后依次是
在这里插入图片描述
我们的每一次操作,都是直接把左边的钢条直接转换成价值。且设每一种切割得到的价值为Cut-Steel[n]i用来代表在第i个位置,切割长度为n的钢条所得到的价值
那么我们每一次切割得到的价值就有如下的规律
在这里插入图片描述
我们这里等号右边的Cut-Steel[n-i]并没有指明切割的位置,为什么?我们往后看。
那我根据这条式子我该如何得到该问题整体的最优解?其实关键还是我们切的位置。
那我们就来求这个切的位置
其实啊,很简单,在长度为n的钢条中(首次切割),我们不是有n-1种方案嘛,那我们设置一个求max的过程,不就能求出n-1种方案里面,最优解是什么吗。
什么?你还是不懂?那我们想想,假设我们切割位置是k哈。那我们当前切割完能拿到手的钱就是p[k]嘛。
那我就不管我前面的部分咯,我后面只剩下n-k长的钢条,那我们现在的问题又回来了,我们要求长度为n-k的钢条的最高总价值嘛。那不就成了,我们问题回到了原点,只不过长度变短了罢了。我只需要在递归的时候,将长度为0设置返回值为0就可以了,那是不是就保证递归策略有出口了。
也就有最优子结构为如下
在这里插入图片描述
那我们接下来写一下伪码表示吧,随后我贴上Cpp的递归代码,应该就一目了然了。

Function CUT-STEEL(p,n)//这里p表示的是价值数组,n表示的是钢条长度
	if(n==0)return 0;//这里表示递归策略的出口
	q=-∞
	i from 1 to n
		q=max(q,p[i]+CUT-STEEL(p,n-i))//每一层循环就是在求切一次的最优
	return q;

建议这里可以根据伪码和自己开发用的趁手的语言去实现一下。
我这里写算法主要还是用C++,Cpp的递归代码如下

#include<iostream>
using namespace std;
int max(int a, int b) {
   
	return a > b ? a : b;
}
int value(int valuesTable[], 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值