矩阵快速幂
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;
}
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;
}
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法
- 基于C++实现的各种内部排序算法汇总
- C++线性时间的排序算法分析
- C++实现汉诺塔算法经典实例
- PHP实现克鲁斯卡尔算法实例解析