【动态规划算法】剪绳子

1. 动态规划概念 [1]

在现实生活中,有一类活动的过程,由于它的特殊性,可将过程分成若干个互相联系的阶段,在它的每一阶段都需要作出决策,从而使整个过程达到最好的活动效果。因此各个阶段决策的选取不能任意确定,它依赖于当前面临的状态,又影响以后的发展。当各个阶段决策确定后,就组成一个决策序列,因而也就确定了整个过程的一条活动路线.这种把一个问题看作是一个前后关联具有链状结构的多阶段过程就称为多阶段决策过程,这种问题称为多阶段决策问题。在多阶段决策问题中,各个阶段采取的决策,一般来说是与时间有关的,决策依赖于当前状态,又随即引起状态的转移,一个决策序列就是在变化的状态中产生出来的,故有“动态”的含义,称这种解决多阶段决策最优化的过程为动态规划方法

2. 基本思想 [2]

动态规划的基本思想是把原问题分解成子问题进行求解,先求解子问题,然后从这些子问题的解得到原问题的解。为了避免子问题重复,我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。

3. 适用条件 [3]

动态规划一般是自顶向下思考,自底向上实现的,适用动态规划的问题必须满足最优化原理和无后效性 。
1、最优化原理(最优子结构性质)
最优化原理可这样阐述:一个最优化策略具有这样的性质,不论过去状态和决策如何,对前面的决策所形成的状态而言,余下的诸决策必须构成最优策略。简而言之,一个最优化策略的子策略总是最优的。一个问题满足最优化原理又称其具有最优子结构性质。
2、无后效性
将各阶段按照一定的次序排列好之后,对于某个给定的阶段状态,它以前各阶段的状态无法直接影响它未来的决策,而只能通过当前的这个状态。换句话说,每个状态都是过去历史的一个完整总结。这就是无后向性,又称为无后效性 。
3、子问题的重叠性
动态规划算法的关键在于解决冗余,这是动态规划算法的根本目的。动态规划实质上是一种以空间换时间的技术,它在实现的过程中,不得不存储产生过程中的各种状态,所以它的空间复杂度要大于其他的算法。选择动态规划算法是因为动态规划算法在空间上可以承受,而搜索算法在时间上却无法承受,所以我们舍空间而取时间 。

4.经典模型

斐波那契数列:F(1)=1,F(2)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 3,n ∈ N*)

5. 应用实例

1. 问题描述
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为k[1],...,k[m]。请问k[1]x...xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
2. 问题分析
我下面所说的子段:被绳子被剪成的每一段都称为子段。
不可再减子段:无论怎么剪,该子段的子段长度乘积都无法达到绳子本身的长度。

由题可知绳子的长度最小为2,当绳子的长度为2时,只有一种剪法(1和1)乘积为1,当绳子的长度为3时,也只有一种剪法(1和2)乘积为2,当绳子的长度为4时,有两种剪法(1和3、2和2)且最大乘积为4,当绳子的长度为5时,有两种剪法(1和4、2和3)且最大乘积为6...
由此递推可以看出当绳子的长度为2或3时,无论怎么剪,子段的乘积都无法达到绳子本身的长度,而当绳子的长度不断增加,总有一种剪法可以使子段长度乘积等于或超过本身长度,所以2和3为不可再剪子段,其中3为最大不可再剪子段。用动态规划算法解决剪绳子问题的思路为:
自顶向下思考:要计算一条绳子子段的最大乘积m,可以把这条绳子分两个子段a和b,分别计算a和b的子段最大乘积m1和m2,再把这两个乘积相乘,由于这a和b的取值有多种情况,所以m1和m2的乘积也有多种情况,最大的那个即为我们要求的最终结果m。的那么这就需我们先分别求a的所有可能取值的子段最大乘积,和b的所有可能取值的子段最大乘积,求法同上,即把a剪成两段c和d,分别计算c和d的子段最大乘积m3和m4,再把这两个乘积相乘,由于这c和d的取值有多种情况,所以m3和m4的乘积也有多种情况,最大的那个即为我们要求的结果m1。b也同理,剪成两段e和f,分别计算e和f的子段最大乘积m5和m6,再把这两个乘积相乘,由于这e和f的取值有多种情况,所以m5和m6的乘积也有多种情况,最大的那个即为我们要求的结果m2。然后就需我们先分别求c,d,e,f的所有可能取值的子段最大乘积,所以再把c,d,e,f分为两段...以此类推不断分下去,直到分到长度为3或3以下,不可再分,因为切了乘积反而会变小。所以这道题的子问题为,求m1,m2,m3,m4,m4,m6......
自底向上实现:因为子段长度为1,2,3时都不可再切,切了乘积反而会变小,所以要求的m值即为自身长度。因此从子段长度为4开始递推,计算子段长度为5,6,7,8,9......时子问题的解(即为该子段的子段的最大乘积),一直递推到子段长度等于目标绳长,这时的结果即为我们要求的结果

3. 代码实现

#include <iostream>
#include <cmath>

using namespace std;

int maxProductOfCuttingRope(int length) {
    if(length < 2)//不满足n>1
        return 0;
    if(length == 2)//绳子长度为2时,结果为1
        return 1;
    if(length == 3)//绳子长度为3时,结果为2
        return 2;



    //绳子长度大于等于4时,新建一个表用于储存子问题的解  
    int* m = new int[length + 1];
    //子段长度小于4时子问题的解
    m[0] = 0;
    m[1] = 1;
    m[2] = 2;  
    m[3] = 3;
    


    //外层循环为:从子子段长度为4开始递推求子问题的解(即为m[i]),一直到子段长度等于绳长(i=length),这时的m[length]即为最终结果
    for(int i = 4; i <= length; ++i) {
        int max = 0;    //i改变 ,对应的max值重置为0
        //内层循环为:当子段长度为i时,把子段分为两段长度为j和i-j,求m[j]和m[i-j]的乘积记为product,j取不同值时product的最大值即m[i],
        //j的值以1为单位递增,以 j = i / 2 为界,当 j > i / 2 时分割方案和前面都是重复的,例如i=7时,分割方案有(1,6)(2,5)(3,4)这三种,从(4,3)开始就是重复的了。
        for(int j = 1; j <= i / 2; ++j) {
            int product = m[j] * m[i - j]; //计算当前j值下m[j]和m[i-j]的乘积product
            //求j取不同值时product的最大值记为max
            if(max < product)
                max = product;
        }
        m[i] = max;//j取不同值时product的最大值max即为m[i]
    }

    int result = m[length];//记录结果,以免下面被销毁
    delete[] m;//销毁打表的辅助空间
    return result; //返回结果
}


int main(){
    cout<<maxProductOfCuttingRope(8)<<endl;
    return 0;
}


感谢阅读,如有问题欢迎指正!


[1][2][3] 引用自百度百科

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343