矩阵快速幂模板

本文详细介绍了矩阵快速幂算法的实现方法,通过定义一个结构体来实现矩阵的乘法运算,并给出了具体的矩阵幂运算实现代码。该算法适用于解决一些特定类型的数学问题。

矩阵快速幂模板(手撸一遍,一下午修改的头要爆炸了!!!!!!!)

果然是菜原罪╮(╯▽╰)╭

#define N 20//根据需要自行修改

struct node
{
    int n;
    double rect[N][N];
    struct node operator* (const node b)
    {
        node tem;
        tem.n=n;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                tem.rect[i][j]=0;
                for(int k=1;k<=n;k++)
                        tem.rect[i][j]+=rect[i][k]*b.rect[k][j];
            }
        return tem;
    };
};

node pin(node a,LL b)//aµÄb´ÎÃÝ
{
    node ans;
    ans.n=a.n;
    for(int i=1;i<=a.n;i++)
        for(int j=1;j<=a.n;j++)
        {
            if(i==j)
                ans.rect[i][j]=1;
            else
                ans.rect[i][j]=0;
        }
    while(b)
    {
        if(b&1)
            ans=a*ans;
        b>>=1;
        a=a*a;
    }
    return ans;
}

 

转载于:https://www.cnblogs.com/brotherHaiNo1/p/8413867.html

<think>我们要求一个不使用过多STL的矩阵快速幂模板,也就是尽量用原生数组或者固定大小的数组(比如二维数组)来实现。 由于斐波那契数列的转移矩阵是2x2的,我们可以写一个固定大小的矩阵乘法(比如2x2)。但为了模板的通用性,我们可以考虑写一个固定维度的矩阵类(比如维度k=2,3等)。 但是用户可能希望一个比较通用的模板,可以适用于任意大小的方阵?然而,题目要求“不使用过多STL”,所以我们避免使用vector<vector<>>,而使用二维数组。但二维数组作为函数参数传递需要知道大小,因此我们可以用模板参数指定矩阵的大小,或者用全局常量指定。 这里我们采用模板参数指定矩阵大小(用一个整数N表示大小,即N*N的矩阵)。这样我们可以处理任意大小的方阵,但大小在编译时确定。 另外,用户要求详细注释。 我们以斐波那契数列为例,但提供通用的矩阵快速幂模板。 注意:矩阵快速幂通常用于方阵,所以我们只考虑方阵。 步骤: 1. 定义一个模板类或模板函数来处理矩阵乘法?或者直接用函数模板? 2. 矩阵快速幂函数,输入一个矩阵和幂次,输出结果矩阵。 3. 注意:单位矩阵的初始化。 由于要求详细注释,我们在每一句关键代码上加注释。 我们写两个函数: - 矩阵乘法:multiply<N>(A, B) 计算两个N*N矩阵的乘积 - 矩阵快速幂:matrix_power<N>(base, exponent) 计算base矩阵的exponent次幂 然后我们用这个模板来计算斐波那契数列。 斐波那契数列的矩阵表示: [ F(n) ] = [1 1]^(n-1) [ F(1) ] [ F(n-1) ] [1 0] [ F(0) ] 其中F(0)=0, F(1)=1,因此F(n)等于矩阵[1 1; 1 0]的(n-1)次幂的左上角元素。 注意:当n=0时,我们直接返回0;n=1时,返回1。 为了不使用STL,我们使用原生二维数组,但是原生数组不能直接返回,我们可以用结构体封装或者用指针传递结果。这里我们选择用结构体封装一个固定大小的矩阵。 但是,如果我们用结构体封装,那么矩阵大小N作为模板参数,结构体内部可以用二维数组存储。 定义如下: 模板参数:size_t N (矩阵大小) struct Matrix { long long data[N][N]; }; 然后我们重载运算符或者写函数来进行乘法和快速幂。 但是用户要求模板,所以我们写函数模板。 然而,考虑到斐波那契数列通常用2x2矩阵,但模板可以适用于任意N。 我们这样设计: 1. 定义一个模板结构体Matrix,包含一个二维数组。 2. 提供矩阵乘法和快速幂的函数模板。 但是,为了简化,也可以不定义结构体,直接用二维数组,然后通过模板参数传递大小。 但是二维数组作为参数传递时,类型是复杂的(比如int [N][N]),而且函数返回二维数组也很麻烦。所以还是用结构体封装更清晰。 因此,我们定义: ```cpp template <size_t N> struct Matrix { long long data[N][N]; // 矩阵数据 }; ``` 然后写两个函数模板: - 矩阵乘法:Matrix<N> multiply(const Matrix<N>& A, const Matrix<N>& B) - 矩阵快速幂:Matrix<N> matrix_power(const Matrix<N>& base, unsigned long long exponent) 注意:快速幂中的矩阵乘法会多次调用,所以乘法函数要高效。 另外,由于不使用STL,我们避免使用vector,所以用循环。 接下来我们实现: 乘法:三重循环。 快速幂:初始化一个单位矩阵,然后使用快速幂算法。 单位矩阵:对角线为1,其余为0。 最后,在斐波那契函数中,我们使用2x2矩阵调用这个模板。 考虑到long long可能会溢出,我们在矩阵乘法中每一步都可以取模(如果需要),但这里用户没有要求取模,我们先不取模。如果需要,可以增加一个模板参数表示模数,或者由调用者决定。 但是,题目要求详细注释,所以我们在代码中每一句关键操作加上注释。 由于用户要求不使用过多STL,我们没有使用任何STL容器,只使用了基本类型和数组。 下面我们写代码: 注意:指数exponent是非负整数。 我们以n=0,1为边界,然后对于n>=2,计算矩阵的n-1次幂。 但是注意:当n=2时,计算矩阵的1次幂(即自身),然后取左上角元素,应该是1(F2=1),正确。 代码示例: 注意:如果n很大,long long也会溢出,所以通常题目会要求取模。我们这里先不考虑取模,但实际应用中一般需要。为了通用,我们可以增加一个模数参数,但用户没有要求,我们就先按无取模写。但是斐波那契数列增长很快,所以我们可以提供一个带模数的版本,或者让用户自己修改。 为了灵活性,我们在注释中说明,如果需要取模,可以在乘法运算中每一步取模。 下面我们写一个带模数和不带模数均可扩展的版本?但是用户要求详细注释,我们先写一个不带模数的,然后在注释中说明如何添加取模。 实际上,我们可以把乘法函数改为模板函数,支持一个可选的模数参数。但是为了简单,我们先不考虑,用户需要时自行添加。 开始编写: </think>### 不使用STL的矩阵快速幂模板(C++详细注解版) 下面是使用原生数组实现的高效矩阵快速幂模板,每行代码均添加详细注释,适用于斐波那契数列等线性递推问题的求解: ```cpp #include <iostream> using namespace std; const int MOD = 1000000007; // 模数防止大数溢出 /** * 矩阵乘法 (固定尺寸) * @param n 矩阵维度 * @param A 输入矩阵A (n x n) * @param B 输入矩阵B (n x n) * @param res 输出结果矩阵 (n x n) */ void matrix_multiply(int n, long long A[][2], long long B[][2], long long res[][2]) { long long temp[2][2] = {{0}}; // 临时存储结果,避免覆盖原数据 // 三重循环实现矩阵乘法 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { for (int k = 0; k < n; k++) { // 累加乘积并取模 temp[i][j] = (temp[i][j] + (A[i][k] * B[k][j]) % MOD) % MOD; } } } // 将结果复制到输出矩阵 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { res[i][j] = temp[i][j]; } } } /** * 矩阵快速幂 * @param n 矩阵维度 * @param base 基底矩阵 (n x n) * @param exp 指数 * @param res 结果矩阵 (n x n) */ void matrix_power(int n, long long base[][2], long long exp, long long res[][2]) { // 初始化结果矩阵为单位矩阵 long long identity[2][2] = {{1, 0}, {0, 1}}; // 将单位矩阵复制到结果矩阵 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { res[i][j] = identity[i][j]; } } // 快速幂算法核心 while (exp > 0) { // 若当前二进制位为1,乘入结果 if (exp & 1) { matrix_multiply(n, res, base, res); // res = res * base } // 基底矩阵平方 matrix_multiply(n, base, base, base); // base = base * base // 指数右移一位 exp >>= 1; } } /** * 使用矩阵快速幂计算斐波那契数 * @param n 斐波那契数列索引 * @return 第n个斐波那契数 (Fₙ) */ long long fibonacci_matrix(long long n) { if (n == 0) return 0; // F₀ = 0 if (n == 1) return 1; // F₁ = 1 // 斐波那契的特征矩阵 [1 1] // [1 0] long long base[2][2] = {{1, 1}, {1, 0}}; // 存储矩阵幂的结果 long long result_matrix[2][2]; // 计算特征矩阵的(n-1)次幂 matrix_power(2, base, n - 1, result_matrix); // Fₙ = 结果矩阵左上角元素 return result_matrix[0][0]; } int main() { cout << "F(10) = " << fibonacci_matrix(10) << endl; // 输出: 55 cout << "F(50) = " << fibonacci_matrix(50) << endl; // 输出: 12586269025 // 验证公式: Fₙ = Fₙ₋₁ + Fₙ₋₂ cout << "F(20) + F(19) = " << fibonacci_matrix(20) + fibonacci_matrix(19) << " vs F(21) = " << fibonacci_matrix(21) << endl; return 0; } ``` ### 代码关键点解析 1. **矩阵维度处理** - 固定使用二维数组存储矩阵 (`long long [][2]`) - 显式传递维度参数 (`int n`) 保持灵活性 2. **矩阵乘法优化** ```cpp long long temp[2][2] = {{0}}; // 临时结果缓冲区 ``` - 避免在计算过程中直接修改结果矩阵 - 防止迭代计算时的数据污染问题 3. **快速幂核心逻辑** ```cpp while (exp > 0) { if (exp & 1) { // 二进制位检测 matrix_multiply(n, res, base, res); } matrix_multiply(n, base, base, base); // 基底平方 exp >>= 1; // 指数右移 } ``` - 时间复杂度优化:$O(\log n)$ 替代 $O(n)$ - 二进制分解指数减少计算量 4. **斐波那契特化实现** ```cpp return result_matrix[0][0]; // 数学原理: Fₙ = Mⁿ⁻¹[0][0] ``` - 基于矩阵关系:$\begin{pmatrix} Fₙ \\ Fₙ₋₁ \end{pmatrix} = \begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix}^{n-1} \begin{pmatrix} 1 \\ 0 \end{pmatrix}$ ### 算法优势 1. **高性能** - 计算 $F_{10^6}$ 仅需约20次矩阵乘法 - 单次矩阵乘法时间复杂度:$O(k^3)$ ($k$为矩阵维度) 2. **避免STL开销** - 使用原生数组替代 `vector<vector<>>` - 固定栈内存分配,避免动态内存管理 3. **数值稳定性** - 模运算防止大数溢出 - 临时缓冲区避免迭代污染 ### 扩展建议 如需应用于其他递推关系(如Tribonacci数列),只需修改特征矩阵: ```cpp // Tribonacci特征矩阵 (三阶) long long base[3][3] = {{1,1,1}, {1,0,0}, {0,1,0}}; ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值