题目
描述
把m个同样的苹果放在n个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?
注意:如果有7个苹果和3个盘子,(5,1,1)和(1,5,1)被视为是同一种分法。
数据范围: 0 ≤ m ≤ 10 , 0 \le m \le 10, 0≤m≤10, 1 ≤ n ≤ 10 1 \le n \le10 1≤n≤10。
输入描述:
输入两个int整数
输出描述:
输出结果,int型
示例1
输入:
7 3
输出:
8
递归
递归分析
设m个苹果放入n个盘子的分法为 f ( m , n ) f(m,n) f(m,n),对盘子n进行分类讨论:
- 1.当 n > m n \gt m n>m时,也就是盘子至少多一个,题目中不考虑顺序的影响,所以用不到的盘子不会影响最终结果,即 f ( m , n ) = f ( m , n − 1 ) f(m, n) = f(m, n - 1) f(m,n)=f(m,n−1)
- 2.当
n
≤
m
时
n \le m时
n≤m时,也就是盘子够了,此时又可以进行两种分类讨论:
- 2.1 至少有一个盘子为空:这种情况类似于情形1,即 f ( m , n ) = f ( m , n − 1 ) f(m, n) = f(m, n-1) f(m,n)=f(m,n−1)。
- 2.2 全部盘子均不为空:每个盘子至少有一个苹果,那么所有盘子中的苹果都拿走一个,每个盘子的相对结果是相同的,即 f ( m , n ) = f ( m − n , n ) f(m,n) = f(m-n,n) f(m,n)=f(m−n,n)
- 上述两种分类讨论方法的分法为:
f
(
m
,
n
)
=
f
(
m
−
n
,
n
)
+
f
(
m
,
n
−
1
)
f(m,n) = f(m-n, n) + f(m, n-1)
f(m,n)=f(m−n,n)+f(m,n−1)
综上所述:
f ( m , n ) = { f ( m , n ) = f ( m , n − 1 ) if n > m f ( m , n ) = f ( m − n , n ) + f ( m , n − 1 ) if n ≤ m f(m,n) = \begin{dcases} f(m, n) = f(m, n - 1) &\text{if } ~ n > m \\ f(m,n) = f(m-n, n) + f(m, n-1) &\text{if } ~ n \le m \end{dcases} f(m,n)={f(m,n)=f(m,n−1)f(m,n)=f(m−n,n)+f(m,n−1)if n>mif n≤m
可以看到,上述的等式,右边是左边减小规模的情况,典型的递归解法,那么递归便需要必要的三要素:结束条件、重复规律、减小规模
- 结束条件:如果只有一个盘子,即 n = 1 n=1 n=1时只有一种放法;如果没有苹果或只有一个苹果,也只有一种放法。所以, n = 1 n=1 n=1 或者 m = 1 m=1 m=1 时均是一种解法, r e t u r n 0 return ~ 0 return 0。
- 重复规律:即上面分析的结果 f ( m , n ) = f ( m , n − 1 ) f(m, n) = f(m, n - 1) f(m,n)=f(m,n−1)或者 f ( m , n ) = f ( m − n , n ) + f ( m , n − 1 ) f(m,n) = f(m-n, n) + f(m,n-1) f(m,n)=f(m−n,n)+f(m,n−1)
- 减小规模: f ( m , n ) = f ( m , n − 1 ) f(m, n) = f(m, n - 1) f(m,n)=f(m,n−1)或者 f ( m , n ) = f ( m − n , n ) + f ( m , n − 1 ) f(m,n) = f(m-n, n) + f(m,n-1) f(m,n)=f(m−n,n)+f(m,n−1)中,每次调用对对m和n均进行规模的减小。
递归代码
"""
当m = 0或m = 1或n = 1,返回1
当n > m, f(m,n) = f(m,n-1)
当n <= m, f(m,n) = f(m-n, n) + f(m,n-1)
"""
def f(m: int, n: int):
if m = 0 or m == 1 or n == 1:
return 1
elif n > m:
return f(m, n - 1)
else:
return f(m-n, n) + f(m,n-1)
m_value, n_value = list(map(int, input().split(' ')))
print(f(m_value, n_value))
动态规划
动态规划如图所示,空了再写逻辑~~~
动态规划代码
先附上代码,分析后面再补~
def dp(m: int, n: int):
arr = [[0 for _ in range(n + 1)] for _ in range(m + 1)]
for i in range(1, n + 1):
arr[0][i] = 1
arr[1][i] = 1
for j in range(m + 1):
arr[j][1] = 1
# 先行再列
for row in range(2, m + 1):
for col in range(2, n + 1):
# 当n <= m, f(m,n) = f(m-n, n) + f(m,n-1)
if row >= col:
arr[row][col] = arr[row - col][col] + arr[row][col - 1]
# 当n > m, f(m, n) = f(m, n - 1)
else:
arr[row][col] = arr[row][col - 1]
return arr[m][n]
逻辑和递归有相似的地方