P3390 【模板】矩阵快速幂

\(P3390\) 【模板】矩阵快速幂

题目传送门

一、矩阵乘法介绍

有两个矩阵:\(A\)\(B\)(矩阵实际上就是二维数组)

\(A\)矩阵和\(B\)矩阵可以做乘法运算必须满足\(A\)矩阵的列的数量等于\(B\)矩阵的行的数量

运算规则:\(A\)的每一行中的数字对应乘以\(B\)的每一列的数字把结果相加起来

二、矩阵乘法模板

1641:【例 1】矩阵 A×B
用户名:littlehb 密码:md******22

#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int n, m, p;
int a[N][N], b[N][N], c[N][N];

//矩阵乘法模板
void mul(int a[][N], int b[][N], int c[][N]) {
    //注意:这里的临时数组t绝不是画蛇添足!
    //因为调用的时候,有时会传递mul(a,b,b)这样的东东,如果每次memset(c,0,sizeof c),
    //就会造成b在运行前被清空,导致结果错误
    int t[N][N] = {0};
    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            for (int k = 0; k < N; k++)
                t[i][j] = t[i][j] + a[i][k] * b[k][j]; //矩阵乘法
    memcpy(c, t, sizeof t);
}
int main() {
    cin >> n >> m;
    // A矩阵 n*m
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            cin >> a[i][j];

    // B矩阵m*p
    cin >> p;
    for (int i = 1; i <= m; i++)
        for (int j = 1; j <= p; j++)
            cin >> b[i][j];

    //矩阵乘法
    mul(a, b, c);

    //输出结果,控制格式
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= p; j++)
            printf("%d ", c[i][j]);
        printf("\n");
    }

    return 0;
}

三、矩阵快速幂

单位矩阵

在普通的乘法中,一个数乘\(1\)还是等于它本身,在矩阵乘法中也有这么一个\(1\),它就是单位矩阵

不同于普通乘法中的单位\(1\),对于不同矩阵他们的单位矩阵大小是不同的

对于\(n∗m\)的矩阵,它的单位矩阵大小为\(m∗m\),对于\(m∗n\)的矩阵,它的单位矩阵大小为\(n∗n\)

也就是说单位矩阵都是正方形的,这是因为只有正方形的矩阵能保证结果和前一个矩阵形状相同

单位矩阵的元素非\(0\)\(1\),从左上角到右下角的对角线上元素皆为\(1\),其他皆为\(0\)

使用单元矩阵

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD = 1e9 + 7;
const int N = 110;
LL n, k;             //本题数据范围很大,用int直接wa哭了
LL a[N][N], b[N][N]; //原始矩阵,结果矩阵

//矩阵乘法模板
void mul(LL a[][N], LL b[][N], LL c[][N]) {
    LL t[N][N] = {0};
    for (LL i = 0; i < N; i++)
        for (LL j = 0; j < N; j++)
            for (LL k = 0; k < N; k++)
                t[i][j] = (t[i][j] + a[i][k] * b[k][j] % MOD) % MOD; //矩阵乘法
    memcpy(c, t, sizeof t);
}

int main() {
    cin >> n >> k;
    //输入原始矩阵
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            cin >> a[i][j];

    // 1、单位矩阵
    for (int i = 0; i < n; i++) b[i][i] = 1;

    // 2、矩阵快速幂
    for (LL i = k; i; i >>= 1) {
        if (i & 1) mul(a, b, b);
        mul(a, a, a);
    }

    // 3、输出
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++)
            printf("%lld ", b[i][j]);
        printf("\n");
    }
    return 0;
}

不使用单元矩阵

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD = 1e9 + 7;
const int N = 110;
LL n, k;             //本题数据范围很大,用int直接wa哭了
LL a[N][N], b[N][N]; //原始矩阵,结果矩阵

//矩阵乘法
void mul(LL a[][N], LL b[][N], LL c[][N]) {
    LL t[N][N] = {0};
    for (LL i = 0; i < N; i++)
        for (LL j = 0; j < N; j++)
            for (LL k = 0; k < N; k++)
                t[i][j] = (t[i][j] + a[i][k] * b[k][j] % MOD) % MOD; //矩阵乘法
    memcpy(c, t, sizeof t);
}

int main() {
    cin >> n >> k;
    // 1、输入原始矩阵
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++) {
            cin >> a[i][j];
            b[i][j] = a[i][j]; //这种解法与标准解法不同,不用构建单位矩阵
            //直接赋值初始化了一个,然后执行k-1次就完成了矩阵的k次幂
        }

    // 2、计算矩阵快速幂
    for (LL i = k - 1; i; i >>= 1) {
        if (i & 1) mul(a, b, b);
        mul(a, a, a);
    }

    // 3、输出
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++)
            printf("%lld ", b[i][j]);
        printf("\n");
    }

    return 0;
}
posted @ 2022-03-22 15:19  糖豆爸爸  阅读(101)  评论(0编辑  收藏  举报
Live2D