您的位置:首页 > 其它

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

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



        我们就会发现即便矩阵快速幂再快,我们计算和我们都是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;
}
(如有错误,欢迎指正,转载请注明出处)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息