本节我们研究矩阵的乘方。
生成单位矩阵
由于矩阵的
次方是单位矩阵,因此有必要先写一个生成单位矩阵的算法。方法很简单,就是写一个for循环,让对角线上的元素为1即可(其余元素在矩阵初始化的时候默认为0,不用管)。下面直接贴出代码:
//mathalgorithm.h
时间复杂度:
(其中
是矩阵规模)
空间复杂度:
普通的乘方算法
现在讨论矩阵的乘方。我们举一个例子,计算
。通常的运算是这样的:
A
我们发现,上述方法需要使用
次乘法运算才能够算出
。一般而言,为计算
,用上述方法需要
次乘法才可以。那能不能改进呢?
快速幂算法
我们采用二分的策略优化它。具体如下所示:
T1
我们发现,按照这种方法去计算,仅仅用了
次乘法运算就能算出
。
我们把如上算法一般化。 下面使用自顶向下的递归方法:
计算
时间复杂度:设为
,其中
是矩阵的幂次。从上述代码中不难得出
。利用主定理,可以解得
空间复杂度:每一次递归调用时新建了一个变量
。由于代码需要执行
次,即递归深度是
,所以空间复杂度是
除此之外,还可以把自顶向下的递归转化为自底向上的循环,代码如下:
//mathalgorithm.h
时间复杂度:
,因为while循环要执行
次
空间复杂度:
,因为只设了常数个变量。
为了加速,这里判断奇偶直接用位与运算符&,除以2用右移运算符>>。
细心的读者可能想到,万一幂次为负数
怎么办?事实上,这需要先求出矩阵的逆
,再让这个逆
做
次方即可。关于求逆矩阵的方法,我们留到解方程组那一块在讨论。
例子:计算斐波那契数列第n项
斐波那契数列定义为:
如果直接递归,那么时间复杂度是
;如果直接递推或者采用动态规划,那么时间复杂度是
。还有更快的做法吗?
注意到,以上递推式可以写成矩阵形式:
用数学归纳法可以证明
由于快速幂的时间复杂度是
,所以用矩阵去计算斐波那契数列第
项的时间复杂度是
。以
为例,代码如下:(在main.cpp中)
//main.cpp
以下是运行结果: