ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

矩阵快速幂

2020-05-17 18:53:47  阅读:219  来源: 互联网

标签:tmp aa int 矩阵 long ++ 快速


快速幂

点击这里

矩阵快速幂

最浅显的作用就是用来求一个矩阵的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\n"); continue;
        }
        bb = pow(tt-1);
        printf("%lld\n", 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

 

标签:tmp,aa,int,矩阵,long,++,快速
来源: https://www.cnblogs.com/Jason66661010/p/12906311.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有