您的位置:首页 > 其它

矩阵快速幂

2016-03-15 16:23 399 查看
矩阵快速幂在动态规划,快速计算矩阵有着非常重要的作用,可以很大程度上减少计算消耗的时间。它的实质其实就是:矩阵计算+快速幂。

1.矩阵乘法

对于矩阵A*B,要遵循的是A的列数要等于B的行数,其他要求没有:

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <ctime>

using namespace std;
const int M = 10000;
typedef long long LL;
typedef vector<int> vec;
typedef vector<vec> Matrix;

//计算矩阵相乘
Matrix mul(Matrix& A, Matrix& B) {
if (A[0].size() != B.size()) {
cerr << "Wrong !" << endl;
exit(0);
}
Matrix C(A.size(), vec(B[0].size()));
for (int i = 0; i < A.size(); i++) {
for (int j = 0; j < B.size(); j++) {
for (int k = 0; k < B[0].size(); k++) {
C[i][k] = (C[i][k] + A[i][j]*B[j][k]) % M;
}
}
}
return C;
}

2.快速幂方法
这在求阶乘中用得最多,其实借用的就是计算机内二进制计数的原则,因为任何一个整数都可以写成Sigma(2^i),所以在实际计算中,对结果会有影响(或者说对结果有贡献)的就是二进制数位上为1的权值,所以,对于一个数的N次方求解可以写成:

//求A的n次方
int res = 1;
while (n > 0) {
if (n & 1) res *= A;
A *= A;
n >> =1;
}

这里举个例子:
要求斐波那契数列的第N项(1<= 10^16),直接暴力肯定会超时(按ACM的标准)。

斐波那契数列的规律是:F(n+2) = F(n+1) + F(n)。怎么和矩阵联系在一起?我们可以发现:

|F(n+1)| |1 1| | F(n) | |1 1|^n |F(1)|
| | = | |*| | ==> | | * | |
| F(n) | |1 0| |F(n-1)| |1 0| |F(0)|

问题解决,而且10^16以内耗时不超过2.7MS,一下是C++代码:
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <ctime>

using namespace std;
const int M = 10000;
typedef long long LL;
typedef vector<int> vec;
typedef vector<vec> Matrix;

//计算矩阵相乘
Matrix mul(Matrix& A, Matrix& B) {
if (A.size() != B[0].size()) {
cerr << "Wrong !" << endl;
exit(0);
}
Matrix C(A.size(), vec(B[0].size()));
for (int i = 0; i < A.size(); i++) {
for (int j = 0; j < B.size(); j++) {
for (int k = 0; k < B[0].size(); k++) {
C[i][k] = (C[i][k] + A[i][j]*B[j][k]) % M;
}
}
}
return C;
}

//计算矩阵阶乘
Matrix Pow(Matrix A, LL n) {
Matrix temp(A.size(), vec(A.size()));
//单位化处理
for (int i = 0; i < A.size(); i++) temp[i][i] = 1;
//快速幂处理
while (n > 0) {
if (n & 1) temp = mul(temp, A);
A = mul(A, A);
n >>= 1;
}
return temp;
}

int main() {
LL n;
double totalTime;
clock_t start, finish;
puts("Please enter a num:");
scanf("%lld", &n);
start = clock();
Matrix A(2, vec(2));
A[0][0] = 1; A[0][1] = 1;
A[1][0] = 1; A[1][1] = 0;
A = Pow(A, n);
finish = clock();
totalTime = (double)(finish - start) / CLOCKS_PER_SEC;
printf("Proceeding time is: %.5lf, The answer is: %d\n", totalTime, A[1][0]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息