C++ 矩阵快速幂

版权声明:转载请保留原地址 https://blog.csdn.net/u012972031/article/details/82726275

缘起:在学这个之前学了好一阵子矩阵,仍然不太懂。。后来发现解斐波那契数列好像只需要方形矩阵就行了,就学了一下方形矩阵的乘法。

先上代码吧

#include<cstdio>
#include<iostream>
#define ll long long
#define mod 1000000007
using namespace std;
struct Mat{
    ll m[101][101];
};
Mat initMat(int n);
Mat Mul(Mat a,Mat b,int n);
Mat poww(Mat a,ll b);
Mat a,e;//a:输入 e:单位矩阵 
int n;//矩阵长度 (每行n个数 ) 
int main(){
    Mat a;
    int k;//k是Mat的指数 
    cin>>n>>k;//input 矩阵长度以及指数
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            cin>>a.m[i][j];
        }
    }

    //初始化e
    for(int i=0;i<n;i++){
        e.m[i][i]=1;
    } 

    Mat c=poww(a,k);

    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            cout<<c.m[i][j]%mod<<" ";
        }
        cout<<endl;
    }

    return 0;
}
Mat poww(Mat a,ll b){
    Mat ans=e,base=a;
    while(b!=0){
        if(b&1){//如果是奇数 
            ans=Mul(ans,a,n);//DEBUG重点 原: Mul(ans,ans,n)
        }
        base=Mul(base,base,n);
        b=b/2;
    }
    return ans;
}
Mat Mul(Mat a,Mat b,int n){//相乘 
    //方形矩阵 n:矩阵长或宽 
    Mat c=initMat(n);
    for(int i=0;i<n;i++){//乘到的行数 
        for(int x=0;x<n;x++){//x坐标
            for(int y=0;y<n;y++){//y坐标 
                c.m[i][x]=c.m[i][x]%mod+a.m[i][y]*b.m[y][x]%mod;
                //c.m[i][x]=c.m[i][x]%mod+a.m[x][i]*b.m[x][y]%mod;
            }
        }
    }
    return c;
}
Mat initMat(int n){//初始化矩阵 n:方形矩阵长或宽 
    Mat c;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            c.m[i][j]=0;
        }
    }
    return c;
}

代码有点长,不过实际上就是基本矩阵+快速幂,等于在快速幂的计算过程中使用矩阵。
不过这样的话,是通不过洛谷的题目的。
题目链接:https://www.luogu.org/problemnew/show/P3390


zxc大佬的指点
1.n,k应为long long类型
2.快速幂的过程中应为 ans=Mul(ans,a,n);

AC代码如下:

#include<cstdio>
#include<iostream>
#define ll long long
#define mod 1000000007
using namespace std;
struct Mat{
    ll m[101][101];
};
Mat initMat(int n);
Mat Mul(Mat a,Mat b,int n);
Mat poww(Mat a,ll b);
Mat a,e;//a:输入 e:单位矩阵 
ll n;//矩阵长度 (每行n个数 ) 
int main(){
    Mat a;
    ll k;//k是Mat的指数 
    cin>>n>>k;//input 矩阵长度以及指数
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            cin>>a.m[i][j];
        }
    }

    //初始化e
    for(int i=0;i<n;i++){
        e.m[i][i]=1;
    } 

    Mat c=poww(a,k);

    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            cout<<c.m[i][j]%mod<<" ";
        }
        cout<<endl;
    }

    return 0;
}
Mat poww(Mat a,ll b){
    Mat ans=e,base=a;
    while(b!=0){
        if(b&1){//如果是奇数 
            ans=Mul(ans,base,n);//DEBUG重点 原: Mul(ans,ans,n)
        }
        base=Mul(base,base,n);
        b=b/2;
    }
    return ans;
}
Mat Mul(Mat a,Mat b,int n){//相乘 
    //方形矩阵 n:矩阵长或宽 
    Mat c=initMat(n);
    for(int i=0;i<n;i++){//乘到的行数 
        for(int x=0;x<n;x++){//x坐标
            for(int y=0;y<n;y++){//y坐标 
                c.m[i][x]=c.m[i][x]%mod+a.m[i][y]*b.m[y][x]%mod;
                //c.m[i][x]=c.m[i][x]%mod+a.m[x][i]*b.m[x][y]%mod;
            }
        }
    }
    return c;
}
Mat initMat(int n){//初始化矩阵 n:方形矩阵长或宽 
    Mat c;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            c.m[i][j]=0;
        }
    }
    return c;
}

总结:

1.应该仔细看好题目的范围要求
2.快速幂的 ans=Mul(ans,base,n); 应当理解透彻

猜你喜欢

转载自blog.csdn.net/u012972031/article/details/82726275