蓝桥杯 python 摆动序列 一文了解动态规划

蓝桥杯 python 摆动序列 一文了解动态规划

题目描述
如果一个序列的奇数项都比前一项大,偶数项都比前一项小,则称为一个摆动序列。即 a 2 i < a 2 i − 1 , a 2 i + 1   > a 2 i a_{2i} < a_{2i-1}, a_{2i+1}\ > a_{2i} a2i<a2i1,a2i+1 >a2i

小明想知道,长度为 m,每个数都是 1 到 n 之间的正整数的摆动序列一共有多少个。

输入描述
输入一行包含两个整数 m,n(1≤n,m≤1000)。

输出描述
输出一个整数,表示答案。答案可能很大,请输出答案除以 10000 的余数。

输入输出样例
示例
输入

3 4

输出

14

动态规划模板
动态规划模板——Python版本这篇博客写的不错。

dp = [] * (n-1)                              # 1.dp数组初始化
dp[x] = []                                   # 2.特殊值赋值
for i in range():                            # 3.循环遍历
	for j in range():
		dp[j] = min(dp[j], dp[i]+ abc[i, j]) # 4.递推公式
print(dp[-1])                                # 5. 输出

解法
下面的方法是一样的,一个没解析,一个有解析。

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

res = m if m > n else n # 动态生成二维数组
dp = [[0 for i in range(res + 2)] for j in range(res + 2)]

for i in range(1, n+ 1): # 初始化为下一行i可以选择的值的数目
    dp[1][i]=n-i+1 # 比如dp11 = 4,即是第一行可选4个

for i in range(2, m + 1):
    if i % 2 == 1:
        for j in range(n, 0, -1):
            dp[i][j]= (dp[i-1][j-1]+dp[i][j+1])%10000

    else:
        for j in range(1, n + 1):
            dp[i][j]=dp[i-1][j+1]+dp[i][j-1]% 10000

ans = dp[m][1] if m % 2 == 1 else dp[m][n]
print(ans)
m, n = map(int,input().split())

res = m if m > n else n # 动态生成二维数组
dp = [[0 for i in range(res + 2)] for j in range(res + 2)]

for i in range(1, n+ 1): # 初始化为下一行i可以选择的值的数目
    dp[1][i]=n-i+1 # 比如dp11 = 4,即是第一行可选4个

# =============================================================================
# 注意 !!!!!!!!
# 第几行代表序列中填的第几个数
# 在奇数行中,dp[i][j]含义为:第i个数选择大于等于j的数时的方案总数。
# 在偶数行中,dp[i][j]含义为:第i个数选择小于等于j的数时的方案总数。
# 注意奇偶 奇偶 奇偶  
# ============================================================================

for i in range(2, m + 1):
    if i % 2 == 1:
        # 奇数行,第i个数填大于等于j有多少种情况
        # 因为大于等于j的情况=等于j的情况 + 大于等于j+1的情况,
        # 而大于等于j+1的情况=等于j的情况 + 大于等于j+2的情况
        # 一直递推累加下去,这里我们从j取最大值开始,采用 倒序 动态记忆化叠加
        for j in range(n, 0, -1):
            dp[i][j]= (dp[i-1][j-1]+dp[i][j+1])%10000# 不要忘了题目方案总数大于10000后要取余
            # 第一轮理解,这一i奇数行 选择大于等于j的方案数 (这时j=n  第一轮)
            #  = 上一行i-1偶数行中选择小于j(即小于等于j-1)的方案 与 最末尾最大的数j组合的方案数(即 dp[i-1][j-1]) +  dp[i][j+1]   (此时dp[i][j+1]=0 ,因为j=n,j+1不在1~n范围,所以为零)

            # 第二轮理解,这一i奇数行选择大于等于j的方案数 (这时j=n--  第二轮)
            #  = 上一行i-1偶数行中选择小于等于j(即小于等于j-1)的方案  与j组合的方案数 (即 dp[i-1][j-1]) 加上  dp[i][j+1] (即 上一轮中这一奇数行j选择大于等于n的方案数)
            # 以此类推
    else:
        # 偶数行 ,第i个数填小于等于j有多少种情况
        # 因为小于等于j的情况=等于j的情况 + 小于等于j-1的情况,
        # 而小于等于j-1的情况=等于j的情况 + 小于等于j-2的情况
        # 一直递推累加下去,这里我们从j取最小值开始,采用 正序 动态记忆化叠加一下
        for j in range(1, n + 1):
            dp[i][j]=dp[i-1][j+1]+dp[i][j-1]%10000
    # 如果m长度为奇数,选择dp[m][1],  如果m长度为偶数,选择dp[m][n]
ans = dp[m][1] if m % 2 == 1 else dp[m][n]
print(ans)

你可能感兴趣的:(蓝桥杯省赛,python,蓝桥杯,开发语言)