蓝桥杯:矩阵之Python题解

【题目描述】
把 1 ∼ 2020 放在 2 × 1010 的矩阵里。要求同一行中右边的比左边大,同一列中下边的比上边的大。一共有多少种方案?
答案很大,你只需要给出方案数除以 2020 的余数即可。

【解题思路】
网上不少人给出了这道题的C语言解题代码,核心的思路是用动态规划,这里有比较详细的解析,在这里直接copy一下代码:

#include <stdio.h>
int DP[1011][1011];
int main()
{
	int i, j;
	DP[1][0] = 1;
	for (i = 1; i <= 1010; i++) DP[i][0] = 1;//初始化
	for (i = 1; i <= 1010; i++) {
		for (j = 1; j <= i; j++) {
			if (i == j) DP[i][j] = DP[i][j - 1];
			else DP[i][j] = (DP[i - 1][j] + DP[i][j - 1]) % 2020;
		}
	}
	printf("%d", DP[1010][1010]);
	return 0;
} 

题目用了1011×1011的二维数组来存储第1行填 i 个数,第2行填 j 个数时可能的情况数,从两层for循环可看出,其本质上是在调用递归。

用Python来解这道题也主要是用动态规划,但由于Python中没有数组这种数据结构,只能用一个dp_func()函数进行递归以代替上面代码中的dp数组的功能,dp[ i ] [ j ] 中的 i 和 j 便成了 dp_func( i, j ) 函数中的两个参数。
翻译过来,在Python中的代码如下:

def dp_func(i,j):
    if j>i:
        return 0
    else:
        if j==0:
            if i==0:
                return 0
            else:
                return 1
        else:
            if j==i:
                return dp_func(i,j-1)
            else:
                return (dp_func(i-1,j)+dp_func(i,j-1))%2020

print(dp_func(1010,1010))

但直接运行这个函数会报错,或是一直运行不出来执行结果,原因是Python当中对递归函数的调用次数存在限制,可使用下面的代码查看递归在本机上的运行上限:

import sys
sys.getrecursionlimit()

也可手动更改递归的运行限制次数:

import sys
sys.setrecursionlimit(9000000) #这里设置大一些

添加上这两句代码后,在Python自带的编辑器中运行程序不报错了,但还是运行不出结果,在网上找原因,有网友解释到,这是因为Python在递归时,每次用到之前的值,都要重新计算一次,如果将结果放到缓存中可提到运行速度,这便要用到 functool 模块中的 lru_cache 装饰器,可使用下面的代码来进行缓存设置:

from functools import lru_cache
@lru_cache(maxsize=2020)

maxsize的值表示设置的最大缓存次数,如果为none则表示没有次数限制。

更改后的完整代码如下:

import sys
sys.setrecursionlimit(9000000) #这里设置大一些
from functools import lru_cache
@lru_cache(maxsize=2020)  #maxsize为缓存的最大次数,为2n时效果最佳,为none则表示不限制

def dp_func(i,j):
    if j>i:
        return 0
    else:
        if j==0:
            if i==0:
                return 0
            else:
                return 1
        else:
            if j==i:
                return dp_func(i,j-1)
            else:
                return (dp_func(i-1,j)+dp_func(i,j-1))%2020

print(dp_func(1010,1010))

这段代码很快在Spyder中执行出结果1340,但在Python自带的编辑器中既不报错,但也不输出结果,还不知道原因,先记在这里。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值