问题描述
每年冬天,北大未名湖上都是滑冰的好地方。北大体育组准备了许多冰鞋,可是人太多了,每天下午收工后,常常一双冰鞋都不剩。
每天早上,租鞋窗口都会排起长龙,假设有还鞋的m个,有需要租鞋的n个。现在的问题是,这些人有多少种排法,可以避免出现体育组没有冰鞋可租的尴尬场面。(两个同样需求的人(比如都是租鞋或都是还鞋)交换位置是同一种排法)
输入格式
两个整数,表示m和n
输出格式
一个整数,表示队伍的排法的方案数。
样例输入
3 2
样例输出
5
数据规模和约定
m,n∈[0,18]
分析:
假设还鞋的都叫A,借鞋子的都叫B,拿题目给的3个人还,2个人借来说,就是A,B的排列组合,手动(小白在线卑微。。。)排出来如下:
AAABB
AABBA
ABABA
ABAAB
AABAB
一共是这五种。我们知道还鞋的必须大于等于借鞋的,即m>=n,我们假设一个递归函数fun_Rec(m, n),返回的是m人还鞋,n人借鞋 的排列数。一个人,要么借鞋要么还鞋。
这个队伍从后面开始看,甲可能是借鞋子的,也可能是还鞋的,所以
fun_Rec(3, 2)就有两种可能:fun_Rec(3, 1),fun_Rec(2, 2)
所以递归关系来了:
fun_Rec(m, n)=fun_Rec(m, n-1)+fun_Rec(m-1, n)
在m>=n的时候递归
在m<n的时候返回0
在n=0的时候(就是没有人借鞋子的时候,只有一种排法)返回1
递归代码:
while True:
try:
def fun_Rec(m,n): #m是还,n是借
if n > m:
return 0
elif n == 0:
return 1
else:
return fun_Rec(m, n-1) + fun_Rec(m-1, n)
s = list(map(int, input().split()))
m, n = s[0], s[1]
print(fun_Rec(m, n))
except:
break
递归可以通过,我们简单想一下,流程可以这样看:
画红色框框的两个是一样的,我们递归的话,就要算两次,于是,我们可以把每次算过的存在一个地方,第二次遇到直接拿来用,于是,我们把代码改成动态规划:
动规的通式很简单:dp[x][y] = dp[x][y-1] + dp[x-1][y]
动规代码:
while True:
try:
s = list(map(int, input().split()))
m, n = s[0], s[1]
dp = [[0 for i in range(0, n+1)] for j in range(0, m+1)]
for i in range(1, m+1):
dp[i][0] = 1 #把没有人借鞋子的那一列都置为1,因为没人借鞋子的时候只有一种排法
for x in range(1, m+1):
for y in range(1, n+1):
if x >= y:
dp[x][y] = dp[x][y-1] + dp[x-1][y]
else:
continue
print(dp[m][n])
except:
break
编程小白记录成长