矩阵的运算 --- 倍增法(UVA11149 - Power of Matrix)

        昨天我们介绍了矩阵的快速幂(点我),相信大家对于矩阵快速幂都有一定的了解。大家也就知道快速幂对于幂运算的迅速,但是当出现了这样的问题:

        我们就会发现即便矩阵快速幂再快,我们计算和我们都是O(n)的算法。那么在这个问题上,我们研究问题的重心就从矩阵的幂,转化为了矩阵幂的和。光看这个好像也想不出什么,那么我们换一个角度来思考这个问题。我们现在是要让计算变得更快,对吧?那么怎么样才能变得更快呢?时间复杂度的定义,就是从运算的次数来衡量时间的吧。那么现在我们就有目标了。我们要怎么减少运算的次数呢?显然就是尽量避免重复计算,换而言之就是尽可能的找出公共部分。于是我们很容易的得到下列式子:


       现在我们发现公共部分,我们已经找到了,提取公因式:


        同理我们还可以继续对式子后半部分(A^1 + A^2 + ...  + A^(n/2) )做相同的处理,于是我们惊奇的发现,我们将O(n)的复杂度降低为 O(log n)的时间复杂度了。

以下是代码实现:

//Matrix 类,同矩阵快速幂的Matrix类

//倍增法求解a^1 + a^2 + ... + a^n
Matrix slove(const Matrix &a, int n){
    //递归终点
    if(n == 1) return a;
    //temp 递归表示a^1 + a^2 + ... + a^(n/2)
    Matrix temp = slove(a, n/2);
    //sum 表示 a^1 + a^2 + ... + a^(n/2) + (a^(n/2))*(a^1 + a^2 + ... + a^(n/2))
    Matrix sum = temp + temp*a.pow(n/2);
    //如果当n为奇数,我们会发现我们的(n/2 + n/2) == n-1
    //于是我们需要补上一项: a^n
    if(n & 1) sum = sum + a.pow(n);
    return sum;
}

       同样的我们来一道题目练练手:UVA11149 - Power of Matrix

这是一道完全的模板题,完整的代码如下:

#include <cstdio>
#include <iostream>
#include <limits.h>
#include <algorithm>
using namespace std;

class Matrix{
public:
    int **m;
    int col, row, mod;
    Matrix(int r = 0, int c = 0, int d = INT_MAX);
    Matrix(const Matrix &value);
    ~Matrix();
    Matrix operator + (const Matrix &rht) const;
    Matrix operator * (const Matrix &rht) const;
    Matrix& operator = (const Matrix &rht);
    Matrix pow(int n) const;
};

Matrix::Matrix(int r, int c, int d):row(r), col(c), mod(d){
    m = new int*[row];
    for(int i = 0; i < row; i++){
        m[i] = new int[col];
    }
    for(int i = 0; i < row; i++){
        for(int j = 0; j < col; j++){
            m[i][j] = 0;
        }
    }
}
Matrix::Matrix(const Matrix &value){
    row = value.row;
    col = value.col;
    mod = value.mod;
    m = new int*[row];
    for(int i = 0; i < row; i++){
        m[i] = new int[col];
    }
    for(int i = 0; i < row; i++){
        for(int j = 0; j < col; j++){
            m[i][j] = value.m[i][j];
        }
    }
}
Matrix::~Matrix(){
    for(int i = 0; i < row; i++){
        delete[] m[i];
    }
    delete[] m;
}
Matrix Matrix::operator + (const Matrix &rht) const{
    Matrix temp(row, col, mod);
    for(int i = 0; i < row; i++){
        for(int j = 0; j < col; j++){
            temp.m[i][j] = (m[i][j] + rht.m[i][j])%mod;
        }
    }
    return temp;
}
Matrix Matrix::operator * (const Matrix &rht) const{
    Matrix temp(row, rht.col, mod);
    for(int i = 0; i < row; i++){
        for(int k = 0; k < rht.row; k++){
            for(int j = 0; j < rht.col; j++){
                temp.m[i][j] = (temp.m[i][j] + m[i][k]*rht.m[k][j])%mod;
            }
        }
    }
    return temp;
}
Matrix& Matrix::operator = (const Matrix &rht){
    for(int i = 0; i < row; i++){
        for(int j = 0; j < col; j++){
            m[i][j] = rht.m[i][j];
        }
    }
    return *this;
}
//矩阵快速幂
Matrix Matrix::pow(int n) const{
    Matrix a(*this), res(row, col, mod);
    for(int i = 0; i < row; i++){
        res.m[i][i] = 1;
    }
    while(n > 0){
        if(n & 1) res = res * a;
        a = a * a;
        n >>= 1;
    }
    return res;
}
//Matrix 类,同矩阵快速幂的Matrix类

//倍增法求解a^1 + a^2 + ... + a^n
Matrix slove(const Matrix &a, int n){
    //递归终点
    if(n == 1) return a;
    //temp 递归表示a^1 + a^2 + ... + a^(n/2)
    Matrix temp = slove(a, n/2);
    //sum 表示 a^1 + a^2 + ... + a^(n/2) + (a^(n/2))*(a^1 + a^2 + ... + a^(n/2))
    Matrix sum = temp + temp*a.pow(n/2);
    //如果当n为奇数,我们会发现我们的(n/2 + n/2) == n-1
    //于是我们需要补上一项: a^n
    if(n & 1) sum = sum + a.pow(n);
    return sum;
}

int main()
{
    int n, k;
    while(scanf("%d%d", &n, &k), n){
        Matrix mat(n, n, 10);
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                scanf("%d", &mat.m[i][j]);
                mat.m[i][j] %= 10;
            }
        }
        Matrix ans = slove(mat, k);
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                if(j) printf(" ");
                printf("%d", ans.m[i][j]);
            }
            printf("\n");
        }
        printf("\n");
    }
    return 0;
}
(如有错误,欢迎指正,转载请注明出处)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章