超基础算法:动态规划

本文深入介绍了动态规划的概念、思想和要素,强调了最优子结构和子问题重叠的重要性。通过解析神奇的兔子问题,展示了动态规划在解决实际问题中的应用,详细分析了解题思路并提供了实现代码。动态规划不仅应用于数学和运筹学,还在工程、经济等多个领域发挥关键作用。
摘要由CSDN通过智能技术生成

算法介绍

动态规划(Dynamic Programming,DP)是运筹学的一个分支,是求解决策过程最优化的过程。20世纪50年代初,美国数学家贝尔曼(R.Bellman)等人在研究多阶段决策过程的优化问题时,提出了著名的最优化原理,从而创立了动态规划。动态规划的应用极其广泛,包括工程技术、经济、工业生产、军事以及自动化控制等领域,并在背包问题、生产经营问题、资金管理问题、资源分配问题、最短路径问题和复杂系统可靠性问题等中取得了显著的效果

算法思想

动态规划的本质其实是一种分治思想,即把原问题分解为若干子问题,先求解最小的子问题,并将结果保存下来作为下一个子问题的参数,依次计算,最后得出原问题的解。

算法要素:

  1. 最优子结构:最优子结构性质是指问题的最优解包含其子问题的最优解。最优子结构是使用动态规划算法的最基本条件,如果不具备最优子结构的性质,就不可以使用动态规划算法解决。
  2. 子问题重叠:子问题重叠是指在求解子问题的过程中,有大量的子问题是重复的,那么只需要求解一次,然后把结果存储在最优子结构中,以便使用时可以直接查询,不需要再次求解。子问题重叠不是使用动态规划的必要条件,但问题存在子问题重叠能够充分彰显动态规划的优势。

算法实战--神奇的兔子

问题描述

假设第1个月有1对刚诞生的兔子,第2个月进入成熟期,第3个月开始生育兔子,而1对成熟的兔子每月会生1对兔子,兔子永不死去……那么,由1对初生兔子开始,12个月后会有多少对兔子呢?

问题分析

我们不妨拿新出生的1对小兔子分析:

第1个月,小兔子①没有繁殖能力,所以还是1对。

第2个月,小兔子①进入成熟期,仍然是1对。

第3个月,兔子①生了1对小兔子②,于是这个月共有2(1+1=2)对兔子。

第4个月,兔子①又生了1对小兔子③。因此共有3(1+2=3)对兔子。

第5个月,兔子①又生了1对小兔子④,而在第3个月出生的兔子②也生下了1对小兔子⑤。共有5(2+3=5)对兔子。

第6个月,兔子①②③各生下了1对小兔子。新生3对兔子加上原有的5对兔子这个月共有8(3+5=8)对兔子。

……

解题思路

一:首先构造最优子结构

兔子分为三个阶段:幼年期、成熟期、生育期。所以可以创建一个数据结构专门用于表示三个阶段的兔子的数量。

二:分析是否存在子问题重叠

本题中,每个月都会有生育期的兔子生小兔子、成熟期的兔子进入生育期、新生的兔子成为幼年期。所以,三种兔子的数量变化即这个问题的子问题。

解题代码

一:最优子结构

//用于保存兔子数量的数据结构
class RabbitsNum{
    //幼年期
    int childhood;
    //成熟期
    int mature;
    //生育期
    int growth;

    RabbitsNum(){
        this.childhood=0;
        this.mature=0;
        this.growth=0;
    }

    @Override
    public String toString() {
        return "childhood=" + childhood + " mature=" + mature + " growth=" + growth ;
    }
}

二:重叠子问题解法

public class MagicRabbits {
    private static RabbitsNum nextMonth(RabbitsNum rabbitsNum){
        //成熟期的兔崽子可以生育了
        rabbitsNum.growth += rabbitsNum.mature;
        //幼年期兔崽子成熟了
        rabbitsNum.mature = rabbitsNum.childhood;
        //生育期的兔子下崽了
        int newRabbit = rabbitsNum.growth;
        //给刚出生的小兔崽子上户口
        rabbitsNum.childhood = newRabbit;

        return rabbitsNum;
    }

    public static void main(String[] args) {
        RabbitsNum rabbitsNum = new RabbitsNum();
        //初始兔子数量
        rabbitsNum.childhood=1;
        System.out.println("第1月 " + rabbitsNum);
        //定义生产月份
        int month = 12;

        for (int i =2; i <= month; i++){
            nextMonth(rabbitsNum);
            System.out.println("第" + i + "月 " + rabbitsNum);
        }
    }
}

计算结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值