斐波那契算法 之 矩阵快速运算 -------COOKIE

目录

 

矩阵相关的算法: 

1.定义: m行n列的矩阵:m X n 的矩阵;

2.矩阵的加减 : 只有同型矩阵才可以进行加减;

3. 常数乘以矩阵

5.矩阵的转置 ,坐标 x  y 互换位置;

6.矩阵乘法       

以上为矩阵相乘基础知识的铺垫:

例题

例题1:斐波那契数列

problem

先来分析一下这道题:

   解决方式: 

     这里先说一下 利用矩阵的一种 工具: 

     递归运算矩阵介绍:

             1.矩阵相乘的预算

             2.矩阵n次幂的快速运算

         下面再看原来的这个题目: 

             构造矩阵式        


矩阵相关的算法: 

1.定义: m行n列的矩阵:m X n 的矩阵;

2.矩阵的加减 : 只有同型矩阵才可以进行加减;

    

        矩阵加满足交换律和结合律,即: 

        A+B=B+A

        (A+B)+C=A+(B+C)

        

 

       3. 常数乘以矩阵

              数乘矩阵满足(λ,μλ,μ为数,A,BA,B为矩阵) 

             (λμ)A=λ(μA)

             (λ+μ)A=λA+μA(λ+μ)A=λA+μA

             λ(A+B)=λA+λB

            

     5.矩阵的转置 ,坐标 x  y 互换位置;

 

             转置满足 

             (AT)T=A

             (λA)T=λAT

             (AB)T=BTAT

             

    6.矩阵乘法
       (矩阵相乘只有在第一个矩阵的列数和第二个矩阵的行数相同时才有意义 )

            设矩阵A为m×p的矩阵,矩阵B为p×n的矩阵,那么A×B的积C是个m×n的矩阵,记C=AB
            中C的第i行第j列为

           

           更容易看一点的 

           
          矩阵相乘满足

                      (AB)C=A(BC)
                      (A+B)C=AC+BC
                      C(A+B)=CA+CB
                      k(AB)=(kA)B=A(kB)
                      (AB)T=BTAT
 

           一定要引起注意的是,矩阵乘法一般不满足乘法交换律! 
          为什么不满足交换律? 
          设A为2×3的矩阵,B为3×5的矩阵,你试试B·A乘的起来吗?

 

 

 

以上为矩阵相乘基础知识的铺垫:

 

例题


例题1:斐波那契数列

problem

 

 

链接:https://www.nowcoder.com/questionTerminal/fd66768dc08748f2be6626f07a02e466
来源:牛客网
 

给出一个整数 n,代表台阶数,一次可以跨 2 个或者 1 个台阶,请输出有多少种走法。

输入描述:

第一行一个整数 n

输出描述:

输出走法数对 1e9 + 7 取模的值。

示例1

输入

3

输出

3

首先来分析一下这道题:

 假如我们在 n阶台阶上面,现在我们有两种选择:

  1. 向下走一阶: 这样 也就到了n-1 层,    n-1 层 有的种类有f( n-1) 

  2. 向下走二阶: 这样 也就到了n-2 层,    n-1 层有的种类有 f( n-2 )    ;

由此可以推出: f(n)=f(n-1)+f(n-2) ; 这中理解方式有点像 动态规划,      由小范围到大范围    --->逐渐递推.所以这样一个简单的for循环就实现了这道题: 

public static void main(String[] args) {
        Scanner sc =new Scanner(System.in);
        int n =sc.nextInt();
        int ss = (int)Math.pow(10, 9)  +7;
        int a=1;int b=1;
        int x;
        for (int i = 3; i <=n; i++) {
            x=b;
            b=a+b;
            a=x;
            if (b>=ss)
                b=b%ss;
        }
        System.out.println(b);
 
    }

然而这样题目是通过不了的

   for循环不通过  :  原因:   

       1.  运行超时  2. 数据太大超出int 或者 long 型 数据

   解决方式: 

     这里先说一下 利用矩阵的一种 工具: 

        递归运算矩阵介绍:

   1.我们现在有几个 已知的值,    可以通过  某种加减乘除的 运算 可以 推导出新的值:

           例如:   

                 已知:      (x0, y0 )    新de满足 :            x1 =2* x0 +y0 ;      y2=x0+y0;

                我们就可以利用乘以一个矩阵来完成这个操作: 

                所以: 可以利用一个矩阵完成一个 向前的运算递推的过程;

        2. 我们在来想一下,利用乘以一个矩阵可以完成一个向前递推的过程,如果连续乘以一个矩阵就可以连续向前递推,

            这里重点是实现了连续向前递推,  也就是说 我们利用矩阵的连续相乘实现了  多次向前的递归 重复运算 .

            这里使用矩阵连续相乘的最大的优点是: 矩阵的连续相乘 也就是矩阵的 n 次幂  可以进行简化运算;

           好了,我们现在来总结一下:    

                  连续递推(规定运算方式) 的问题---->矩阵的连续相乘---->矩阵的n次幂----->矩阵n次幂(数特别大的话 可以进行 拆分二                    进制简化运算)

      好了,以上介绍的是这样利用矩阵的一种工具,这种工具的实现需要两个插件: 

             1.矩阵相乘的预算


    /***
     * 矩阵的相乘;
     * @param a
     * @param b
     * @return
     */
    private static long[][] XiangCheng(long[][] a, long[][] b) {

        if (a==null || b==null || a[0].length!=b.length)
            return null;
        int ss = (int)Math.pow(10, 9)  +7;

        int n =a.length;
        int m =b[0].length;

        long[][] c=new long[n][m];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                int x=0;
                // 新矩阵中新个体元素的求出
                for (int k = 0; k <b.length ; k++) {

                    long y=a[i][k]*b[k][j];
                    if (y>ss)
                        y=y%ss;
                    x+=y;

                    if (x>ss)
                        x=x%ss;
                }

                c[i][j]=x;
            }
        }

        return c;

    }

             2.矩阵n次幂的快速运算


    private static long[][] quickGetMi(long[][] a, long t) {

        if (a==null || a.length!=a[0].length)
            return null;

        double x=  Math.log(t)/Math.log(2);
        //1System.out.println((int)x);

        long[][][] h=Init(a,(int)x+1);

        int i=0;
        long[][] result =null;
        while (t!=0){

            long i1 = t & 1;
            if (i1!=0){
                if (result==null)
                    result=h[i];
                else
                    result=XiangCheng(result,h[i]);
            }
            t=t>>1;
            i++;
        }



        return result;
    }

    private static long[][][] Init(long[][] a, int x) {

        long[][][] g=new long[x][a.length][a[0].length];
        g[0]=a;
        for (int i = 1; i < x; i++) {
            g[i]=XiangCheng(g[i-1],g[i-1]);
        }

        return g;
    }

 

         利用矩阵快速运算的功能介绍完了: 实现快速的连续相同的递推运算;

         下面再看原来的这个题目: 

              为了更高效地解决这道题,我们就必须用矩阵乘法了 
              使用矩阵乘法,我们需要数学建模,构造矩阵式 
            (构造矩阵式是解决矩阵乘法类的题目最重要的步骤,例如DP推状态一样)

             

             构造矩阵式
             现在,我们有         A=(f[x−1],f[x−2])                B=(f[x],f[x−1]) 
             我们就构造一个矩阵T使得
             A×T=B

            如何构造?

            f[x−1]f[x−1]对f[x]f[x]的贡献为f[x−1]∗1f[x−1]∗1,所以T1,1=1T1,1=1
            f[x−2]f[x−2]对f[x−1]f[x−1]的贡献为f[x−2]∗1f[x−2]∗1,所以T1,2=1T1,2=1
            f[x−1]f[x−1]对f[x−1]f[x−1]的贡献为f[x−1]∗1f[x−1]∗1,所以T2,1=1T2,1=1
            f[x−2]f[x−2]对f[x−1]f[x−1]的贡献为f[x−2]∗0f[x−2]∗0,所以T2,2=0T2,2=0
            这个矩阵就是——(1,1)(1,0)
            那么斐波那契数列的另一种通项公式我们就可以轻松地写出来了—— 
            (f[n−1],f[n−2])×(1,11,0)=(f[n],f[n−1])
            ( f[n−1],f[n−2])×(1,11,0)=(f[n],f[n−1])

            so—— 
            (f[1],f[0])×(1,11,0) n−1 次方 =(f[n],f[n−1])

 

            这样我们利用上面介绍的这种利用矩阵相乘递归的这种公式,就可以解决这个问题了,还有需要注意的是:要进行不断取余,                防止数值过大;
 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值