信息素养大赛Python挑战赛之动态规划算法

信息素养大赛Python挑战赛往年第六题详解

分钱方案(往年信息素养复赛真题)

题目描述
有n个人,他们需要分配m元钱(m>n),每个人至少分到1元钱,且每个人分到的钱数必须是整数。请问有多少种分配方案?

输入描述

输入一行两个正热数n,m,用空格间隔。

输出描述

输出分配方案数。

样例输入

5 10

样例输出

126

问题分析

  1. 初始状态:
  • 如果没有人(即i=0),那么没有方案,方案数为0。
  • 如果没有钱(即j=0),那么唯一的方案就是所有人都分到 0元钱,但这种情况不符合每个人至少1 元钱的条件,方案数为0。

如下表所示:
在这里插入图片描述

  1. 转移方程
    如i=3,j=5,代表我们将5元钱分给3个人,方案数用f(i,j)表示,所有方案如下:
  • 最后一人分1元,其余两人分剩余的4元,方案数为f(i-1, j-1);
  • 最后一人分2元,其余两人分剩余的3元,方案数为f(i-1, j-2);
  • 最后一人分3元,其余两人分剩余的2元,方案数为f(i-1, j-3);
  • 最后一人分4元,其余两人分剩余的1元。不符合要求,方案数为0。
  • 最后一人分5元,其余两人分剩余的0元。不符合要求,方案数为0。
    综上所述,方案数f(i,j) = f(i-1,j-1) + f(i-1, j - 2) + … + f(i -1, i-1)在这里插入图片描述

因为 f(i-1, j - 2) + … + f(i -1, i-1) = f(i, j-1)所以状态转移方程为:f(i,j) = f(i-1,j-1) + f(i, j-1)在这里插入图片描述

3.边界条件:
我们定义一个二维列表dp ,其中dp[i][j]表示将j元钱分配给i个人的方案数。

  • dp[1][1]=1表示1个人,1元钱,只有一种方案。
  • m<n时,钱数少于人数,方案数为0。

参考代码【递归】

def f(n, m):
    if m < n:
        return 0
    if n == 1:
        return 1
    count = 0
    for i in range(1, m - n + 2):# 递归计算 f(i-1,j-1) **+ f(i-1, j - 2) + ... + f(i -1, i-1)
        #  i的值最大为m-n+1
        count += f(n - 1, m - i)# 从f(n-1, m-1) 到 f(n-1, m-(m-n+1))即f(n-1,n-1)累加求和
    return count

n, m =map(int,input().split())
print(f(n, m))

参考代码篇【动态规划】

n, m = map(int,input().split())
dp =[[0]*(m+1) for i in range(n+1)]
for j in range(1, m+1):
    dp[1][j]=1  # 大于等于1元时,只有1人分配方案有1种
for i in range(2, n+1):
    for j in range(i, m+1):# 从i开始,j小于i不需要计算
        dp[i][j]= dp[i-1][j-1] + dp[i][j-1]
print(dp[n][m])

递归和动态规划是解决很多算法问题的两种重要方法,尤其在处理需要重复子问题求解的问题时非常有效。尽管它们在某些方面相似,但在效率、内存使用以及实现方式上有着显著的区别。

递归

递归是一种通过函数调用自身来解决问题的方法。递归通常用于解决可以分解为相似子问题的问题,其中每个子问题都是原问题的一个更小版本。递归的关键在于找到一个基准情况(或称为基本情况),它是递归的停止条件,确保递归调用能够终止。

优点

简洁:代码通常比迭代方法更简洁,更容易理解。 通用:适用于许多类型的问题,尤其是那些可以自然分解为子问题的问题。

缺点

可能导致大量的重复计算:如果没有适当的记忆化或缓存机制,相同的子问题可能会被多次计算。 栈溢出风险:对于深层递归,可能会耗尽调用栈空间。

动态规划

动态规划是另一种解决优化和计数问题的方法,它通过将原问题分解为相对简单的子问题的方式求解,并且存储子问题的解以避免重复计算。动态规划通常与填表法(或称为自底向上方法)和记忆化递归(自顶向下加记忆化)相关联。

优点

高效:通过避免重复计算,动态规划通常比简单的递归实现要快得多。
易于实现记忆化:对于递归方法,添加记忆化可以显著提高效率,使其更接近动态规划的效率。

缺点

可能需要额外的空间来存储子问题的解。 问题分解和状态定义需要一定的技巧和经验。

总结

对于小规模问题或易于理解的问题,递归可能是更好的选择。然而,对于需要处理大量数据或追求高性能的场景,动态规划通常是更好的选择。在某些情况下,记忆化递归可以作为一种折衷方案,它结合了递归的简洁性和动态规划的效率。

  • 16
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伶俐角少儿编程

伶俐角少儿编程公众号~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值