数学建模笔记——动态规划

数学建模笔记------动态规划

  • 动态规划
    • [1. 模型原理](#1. 模型原理)
    • [2. 典型例题](#2. 典型例题)
      • [2.1 例1 凑硬币](#2.1 例1 凑硬币)
      • [2.2 例2 背包问题](#2.2 例2 背包问题)
    • [3. python代码实现](#3. python代码实现)
      • [3.1 例1](#3.1 例1)
      • [3.2 例2](#3.2 例2)

动态规划

1. 模型原理

动态规划是运筹学的一个分支,通常用来解决多阶段决策过程最优化问题。动态规划的基本想法就是将原问题转换为一系列相互联系的子问题,然后通过逐层地推来求得最后的解。目前,动态规划常常出现在各类计算机算法竞赛或者程序员笔试面试中,在数学建模中出现的相对较少,但这个算法的思想在生活中非常实用,会对我们解决实际问题的思维方式有一定启发。

动态规划组成部分:

  1. 确定状态:解动态规划的时候需要开一个数组,数组的每个元素需要明确代表什么,类似于确定数学题中X、Y的含义
  2. 转移方程:把状态表达成方程
  3. 初始条件和边界情况
  4. 计算顺序

2. 典型例题

2.1 例1 凑硬币

你有三种硬币,分别面值2元、5元和7元,每种硬币都有足够多,买一本书需要27元,如何用最少的硬币组合起来正好付清,不需要对方找钱

  1. 确定状态

    • 最后一步:

      虽然我们不知道最优策略是什么,但是最优策略肯定是有k校硬币, a 1 , a 2 , . . . . . . a k a_1,a_2,......a_k a1,a2,......ak加起来面值为27,所以一定存在有最后一枚硬币: a k a_k ak,除了这枚硬币,前面的面值加起来是 27 − a k 27-a_k 27−ak,两个关键点:

      • 我们不关心前面的 k − 1 k-1 k−1枚硬币是怎么拼出 27 − a k 27-a_k 27−ak的(可能有很多种拼法),而且我们现在甚至还不知道 a k a_k ak和 k k k是多少,但我们可以确定前面的硬币拼出了 27 − a k 27-a_k 27−ak
      • 因为是最优策略,所以拼出 27 − a k 27-a_k 27−ak的硬币数一定要最少,否则就不是最优策略
    • 子问题:

      • 最少可以用多少枚硬币拼出 27 − a k 27-a_k 27−ak
      • 原问题是最少可以用多少枚硬币可以拼出27
      • 我们将原问题可以转化为一个规模更小的子问题: 27 − a k 27-a_k 27−ak
    • 状态:

      我们可以设状态 f ( x ) = 最少用多少枚硬币拼出 x f(x)=最少用多少枚硬币拼出x f(x)=最少用多少枚硬币拼出x

  2. 转移方程

    对于任意 x x x
    f [ x ] = m i n { f [ x − 2 ] + 1 , f [ x − 5 ] + 1 , f [ x − 7 ] + 1 } f[x]=min\{f[x-2]+1,f[x-5]+1,f[x-7]+1\} f[x]=min{f[x−2]+1,f[x−5]+1,f[x−7]+1}

  3. 初始条件和边界情况

    • 转移方程有两个问题
      • x − 2 , x − 5 , 或 x − 7 x-2,x-5,或x-7 x−2,x−5,或x−7小于0怎么办
      • 什么时候停下来
    • 所以:
      • 如果不能拼出Y,那么就定义 f [ Y ] = f[Y]= f[Y]=正无穷,例如 f [ − 1 ] = f [ − 2 ] = f [ − 3 ] = ⋯ = f[-1]=f[-2]=f[-3]=\cdots= f[−1]=f[−2]=f[−3]=⋯=正无穷
      • 所以 f [ 1 ] = min ⁡ { f [ − 1 ] + 1 , f [ − 4 ] + 1 , f [ − 6 ] + 1 } = f[1]=\operatorname*{min}\{f[-1]+1,f[-4]+1,f[-6]+1\}= f[1]=min{f[−1]+1,f[−4]+1,f[−6]+1}=正无穷,表示拼不出来
      • 初始条件 f [ 0 ] = 0 f[0]=0 f[0]=0
  4. 计算顺序

    • 拼出 x x x所需要的最少硬币数: f [ x ] = m i n { f [ x − 2 ] + 1 , f [ x − 5 ] + 1 , f [ x − 7 ] + 1 } f[x]=min\{f[x-2]+1,f[x-5]+1,f[x-7]+1\} f[x]=min{f[x−2]+1,f[x−5]+1,f[x−7]+1}
    • 初始条件: f [ 0 ] = 0 f[0]=0 f[0]=0
    • 然后计算 f [ 1 ] , f [ 2 ] , . . . , f [ x ] f[1],f[2],...,f[x] f[1],f[2],...,f[x]

2.2 例2 背包问题

有一个小偷去偷东西,他的背包可以容纳总重量为 W W W的物品,现在有 n n n件物品,每件物品的重量为 w i w_i wi, 价值为 v i v_i vi ,求能够放进背包的物品的最大价值。

  1. 状态: d p [ i ] [ j ] dp[i][j] dp[i][j]表示前 i i i件物品放入容量为 j j j的背包中所获得的最大价值

  2. 状态转移方程:对于第 i i i件物品,可以选择放或不放

    • 如果不放,那么 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i−1][j]

    • 如果放,那么 d p [ i ] [ j ] = d p [ i − 1 ] [ j − w i ] + ν i dp[i][j]=dp[i-1][j-w_i]+\nu_i dp[i][j]=dp[i−1][j−wi]+νi

    • 选择获得最大价值的情况,即
      d p [ i ] [ j ]   =   m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − w i ]   +   v i ) dp[i][j]\:=\:max(dp[i-1][j],dp[i-1][j-w_i]\:+\:v_i) dp[i][j]=max(dp[i−1][j],dp[i−1][j−wi]+vi)

  3. 初始条件:

    • d p [ 0 ] [ 0 ] = 0 dp[ 0] [ 0] = 0 dp[0][0]=0,将前0个物品放入容量为0的背包中能获得的最大价值为0
    • 如果容量为 0,则无法放入任何物品, d p [ i ] [ 0 ] = 0 dp[i][0]=0 dp[i][0]=0
    • 如果没有物品可选,则无法放入任何物品, d p [ 0 ] [ j ] = 0. dp[0][j]=0. dp[0][j]=0.
  4. 求解顺序:从第一个物品开始,求解到 n n n

最终, d p [ n ] [ W ] dp[n][W] dp[n][W]即为问题的解

3. python代码实现

3.1 例1

python 复制代码
def coinChange(n):
    """用于计算找零的最少硬币数

    Args:
        n (int): 需要找零的金额
    return:
        int: 最少硬币数,如果无法找零则返回-1
    """
    dp = [float('inf')]*(n+1)  # 初始化动态规划数组
    dp[0] = 0  # 金额为0时,最少硬币数为0
    for i in range(1, n+1):
        for j in [2, 5, 7]:
            if i >= j:
                dp[i] = min(dp[i], dp[i-j]+1)
    if dp[n] == float('inf'):
        return -1
    else:
        return dp[n]


n = int(input("请输入需要找零的金额:"))
res = coinChange(n)
print("最少硬币数为:", res)

测试结果:

复制代码
请输入需要找零的金额:27
最少硬币数为: 5

3.2 例2

python 复制代码
def knapsack(weights, values, capacity):
    """用于求解0-1背包问题的动态规划算法

    Args:
        weights (int): 物品的重量列表
        values (int): 物品的价值列表
        capacity (int): 背包的容量
    return:
        int: 背包能装的最大价值
    """
    n = len(weights)  # 物品的数量
    dp = [[0 for j in range(capacity+1)] for i in range(n+1)]  # 初始化动态规划数组

    # 动态规划求解过程
    for i in range(1, n+1):
        for j in range(1, capacity+1):
            if j < weights[i-1]:
                dp[i][j] = dp[i-1][j]
            else:
                dp[i][j] = max(dp[i-1][j], dp[i-1][j-weights[i-1]]+values[i-1])
    return dp[n][capacity]


w = input("请输入物品的重量列表(用逗号隔开):")
v = input("请输入物品的价值列表(用逗号隔开):")
weights = [int(i) for i in w.split(",")]
values = [int(i) for i in v.split(",")]
c = int(input("请输入背包的容量:"))
res = knapsack(weights, values, c)
print("背包能装的最大价值为:", res)

输入及输出:

复制代码
请输入物品的重量列表(用逗号隔开):1,2,3
请输入物品的价值列表(用逗号隔开):3,4,5
请输入背包的容量:5
背包能装的最大价值为: 9

请输入物品的重量列表(用逗号隔开):1,2,3
请输入物品的价值列表(用逗号隔开):4,5,6
请输入背包的容量:5
背包能装的最大价值为: 11
相关推荐
ytttr87335 分钟前
matlab通过Q学习算法解决房间路径规划问题
学习·算法·matlab
精灵vector1 小时前
构建专家级SQL Agent交互
python·aigc·ai编程
Zonda要好好学习2 小时前
Python入门Day2
开发语言·python
Vertira2 小时前
pdf 合并 python实现(已解决)
前端·python·pdf
寻丶幽风2 小时前
论文阅读笔记——NoPoSplat
论文阅读·笔记·三维重建·3dgs·相机位姿·dustr
太凉2 小时前
Python之 sorted() 函数的基本语法
python
go54631584652 小时前
修改Spatial-MLLM项目,使其专注于无人机航拍视频的空间理解
人工智能·算法·机器学习·架构·音视频·无人机
项目題供诗2 小时前
黑马python(二十四)
开发语言·python
油泼辣子多加2 小时前
【Torch】nn.BatchNorm1d算法详解
算法
nlog3n2 小时前
基于 govaluate 的监控系统中,如何设计灵活可扩展的自定义表达式函数体系
算法·go