zoukankan      html  css  js  c++  java
  • 矩阵快速幂

    快速幂

    点击这里

    矩阵快速幂

    最浅显的作用就是用来求一个矩阵的n次幂,就是将快速幂中的数字映射成矩阵

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    #define N 102
    #define mod 1000000007//一般会对结果进行取余
    int tmp[N][N],ans[N][N],ori[N][N];//ori是输入的矩阵,ans是承接结果的矩阵,tmp是临时矩阵
    void mul(int a[][N],int b[][N], int n)
    {
        //fill(tmp[0], tmp[0] + N*N, 0);
        memset(tmp, 0, sizeof tmp);
            for (int i = 0; i < n; i++)//矩阵的乘法
                for (int j = 0; j < n; j++)
                    for (int k = 0; k < n; k++)
                    tmp[i][j] +=(a[i][k] * b[k][j]%mod)%mod;
        for (int i = 0; i < n; i++)//将tmp矩阵复制到a矩阵
            for (int j = 0; j < n; j++)
                a[i][j] = tmp[i][j];
    }
    
    void pow(int a[][N], int power)
    {
        memset(ans, 0, sizeof ans);//n是幂,N是矩阵大小
        for (int i = 0; i < N; i++)
            ans[i][i] = 1;//设置为单位矩阵(与快速幂中的result是是一样的作用)
        while (power)//与单个数字的快速幂一样
        {
            if (power & 1)
                mul(ans, a, N);//是奇数就用ans承接结果
            power >>= 1;
            mul(a, a, N);//是偶数就执行a的平方来降幂
        }
    }
    int main()
    {
        std::ios::sync_with_stdio(false);
        std::cin.tie(0);
        std::cout.tie(0);
        int n,k;
        cin >> n >> k;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                cin >> ori[i][j];
        pow(ori, k);
        
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
                printf("%s%d", j == 0 ? "" : " ", ans[i][j]);//输出结果
            cout << endl;
        }
    
    }

    实用代码

    上面的代码只是为了较好地理解矩阵快速幂的算法实现,但是其中涉及到矩阵的复制、较多的初始化,在实际解题中会不适用,故如下给出实用代码

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    #define N 102
    #define mod 1000000007
    struct matrix//使用struct
    {
        long long c[N][N];
    }aa, bb;//注意:在这里初始化的aa、bb矩阵中默认值为0(aa表示初始矩阵,bb表示计算的结果矩阵)
    long long ans[N][N], ori[N][N];
    long long n, k;
    matrix mul(matrix a, matrix b)
    {
        matrix tmp;//这里初始化矩阵中的值为随机数,所以要将其设为0(也是为了后续的函数中能够使用tmp而不影响结果)
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                tmp.c[i][j] = 0;
    
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                for (int k = 0; k < n; k++)
                    tmp.c[i][j] = (tmp.c[i][j] + (a.c[i][k] * b.c[k][j]) % mod) % mod;
        return tmp;//直接返回struct结构体,不用矩阵复制
    }
    
    matrix pow(long long power)
    {
        matrix ans;//这里初始化矩阵中的值为随机数,所以要将其设为0,对角线置为1,表示一个单位矩阵,否则后续结果会出错
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
            {
                if (i == j)ans.c[i][j] = 1;
                else ans.c[i][j] = 0;
            }
    
        while (power)//与单个数字的快速幂一样
        {
            if (power & 1)
                ans = mul(ans, aa);
            power >>= 1;
            aa = mul(aa, aa);
        }
        return ans;
    }
    int main()
    {
        scanf("%lld%lld", &n, &k);
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                scanf("%lld", &aa.c[i][j]);
        bb = pow(k);
    
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
                printf("%s%lld", j == 0 ? "" : " ", bb.c[i][j]);
            cout << endl;
        }
    
    }

    实用代码优化【模板】

    上面代码的单位矩阵是后面新建的,而我们可以直接使用bb作为单位矩阵 给出矩阵快速幂的最后模板

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    #define N 102
    #define mod 1000000007
    struct matrix
    {
        long long c[N][N];
    }aa,bb;
    long long ans[N][N], ori[N][N];
    long long n, k;
    matrix mul(matrix a, matrix b)
    {
        matrix tmp;    
        for (int i = 0; i < n; i++)//这里初始化矩阵中的值为随机数,所以要将其设为0(也是为了后续的函数中能够使用tmp而不影响结果)
            for (int j = 0; j < n; j++)
                tmp.c[i][j] = 0;
    
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                for (int k = 0; k < n; k++)
                    tmp.c[i][j] =(tmp.c[i][j]+ (a.c[i][k] * b.c[k][j]) % mod) % mod;//注意这里的取余方式,现在乘法取余,防止在乘法就溢出
        return tmp;//直接返回struct结构体,不用矩阵复制
    }
    
    matrix pow(long long power)
    {
        for (int i = 0; i < n; i++)
            bb.c[i][i] = 1;//使用bb作为单位矩阵来承接结果
        while (power)//与单个数字的快速幂一样
        {
            if (power & 1)
                bb=mul(bb, aa);
            power >>= 1;
            aa=mul(aa, aa);
        }
        return bb;
    }
    int main()
    {
        scanf("%lld%lld", &n, &k);
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                scanf("%lld",&aa.c[i][j]);
        bb=pow( k);
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
                printf("%s%lld", j == 0 ? "" : " ", bb.c[i][j]);
            cout << endl;
        }
    }

    简单练习

    https://www.luogu.com.cn/problem/P3390(使用模板代码即可解决)

    矩阵快速幂的用途

    求解递推式的值(就像是高中数学的那种)

    例题:https://www.luogu.com.cn/problem/P1939

    解题步骤

    第一步:列出递推式:ax=ax-1+ax-3(x>3)

    第二步:ax最早是由ax-3三而来,而矩阵快速幂所解决的问题范围又是方阵,所以我们构造需要一个3*3的方阵

    第三步:推理

    这是第n项AN这是第n-1项AN-1于是我们构造的矩阵ans应该满足

    将第n-1项横过来:f[n-1]  f[n-2]  f[n-3]  

    f[n]= f[n-1]+f[n-3] :      1         0        1  (只需要f[n-1]    f[n-3]  )

     f[n-1]                   :      1         0        0  (第n-1项中有f[n-1]  )

     f[n-2]                   :      0         1        0  (第n-1项中有f[n-2]  )

     于是构造的ans矩阵就出来了

    第四步:求解

    这样一来就求出一个等比数列:An=ans*An-1——>An=ansn-1*A1(这里的A1就是【1 1 1 】即 初始a1 a2 a3的值)

    代码

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    #define N 102
    #define mod 1000000007
    struct matrix
    {
        long long c[N][N];
    }aa, bb;
    long long ans[N][N], ori[N][N];
    long long n, k;
    matrix mul(matrix a, matrix b)
    {
        matrix tmp;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                tmp.c[i][j] = 0;
    
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                for (int k = 0; k < n; k++)
                    tmp.c[i][j] = (tmp.c[i][j] + (a.c[i][k] * b.c[k][j]) % mod) % mod;
        return tmp;
    }
    
    matrix pow(long long power)
    {
        for (int i = 0; i < n; i++)
            bb.c[i][i] = 1;
        while (power)//与单个数字的快速幂一样
        {
            if (power & 1)
                bb = mul(bb, aa);
            power >>= 1;
            aa = mul(aa, aa);
        }
        return bb;
    }
    int main()
    {
        aa.c[0][0] = aa.c[0][2] = aa.c[1][0] = aa.c[2][1] = 1;//为初始的aa矩阵赋值(就是分析中的ans矩阵)
        n = 3;//矩阵的大小为3
        scanf("%lld",&k);
        for (int i = 0; i < k; i++)
        {
            long long tt;
            scanf("%lld", &tt);
            if (tt <= 3)
            {
                printf("1
    "); continue;
            }
            bb = pow(tt-1);
            printf("%lld
    ", bb.c[0][0]);//在An项中,她是一个三行一列的矩阵,而所求的an就是第一行的值
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    bb.c[i][j] = 0; aa.c[i][j] = 0;//因为要求多次,所以要重新初始化aa、bb矩阵
                }
            }
            aa.c[0][0] = aa.c[0][2] = aa.c[1][0] = aa.c[2][1] = 1;
        }
    
    }

    参考:https://blog.csdn.net/zhangxiaoduoduo/article/details/81807338https://blog.csdn.net/red_red_red/article/details/90208713、https://www.luogu.com.cn/blog/_post/101179

     
  • 相关阅读:
    最常用和最难用的控件--ListView(Android第一行代码)
    LayoutInflater的使用
    JAVA的网络编程【转】
    Android 程序调试
    android Log日志使用
    Android Animation
    实现ImageView宽度填满屏幕
    Android ViewPager使用详解
    对另一个布局文件里的Button按钮进行监听
    如何在一个Activity里使用另一个xml布局文件
  • 原文地址:https://www.cnblogs.com/Jason66661010/p/12906311.html
Copyright © 2011-2022 走看看