Fibonacci数列就形如:0, 1, 1, 2, 3, 5, 8, 13, ....
现在要求输入一个整数n,请你输出斐波那契数列的第n项
可以看出 第1项为0, 第2项为1, 第三项为1, 第四项为2 = 第三项+第二项, ...... 第n项 = 第(n-1)项+第(n-2)项
即 f(n) = f(n-1) + f(n-2)
设 A为m×p 的矩阵,B为p×n 的矩阵,那么称 m×n 的矩阵 C为 矩阵 A 和 B 的乘积,记作C = AB
=> f(n) = C(0,0)
又矩阵乘法满足结合律,即
(AB)C = A(BC)(AB)C=A(BC)
那我们就需要求出 A^(n-1)
例如 4 = 100
4 = 1 * 2 ^(2) + 0 * 2 ^(1) + 0 * 2 ^(0)
A = A ^(1*2^(2)) * A ^(0*2^(1)) * A ^(0*2^(0))
代码:
public static class Matrix {
int[][] value;
int row, col;
Matrix(int row, int col) {
value = new int[row][col];
this.row = row;
this.col = col;
}
Matrix(int row, int col, int op) {
value = new int[row][col];
this.row = row;
this.col = col;
int minRowCol = row < col ? row : col;
for (int i = 0; i < minRowCol; i++) {
value[i][i] = op;
}
}
Matrix(Matrix matrix) {
value = new int[matrix.row][matrix.col];
this.row = matrix.row;
this.col = matrix.col;
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
value[i][j] = matrix.value[i][j];
}
}
}
Matrix multiply(Matrix matrix) {
Matrix ret = new Matrix(row, col);
for(int i = 0; i < row; i++) {
for(int j = 0; j < matrix.col; j++) {
for(int k = 0; k < col; k++) {
ret.value[i][j] += value[i][k] * matrix.value[k][j];
}
}
}
return ret;
}
Matrix power(int n) {
Matrix ret = new Matrix(row, col, 1);
Matrix matrix = new Matrix(this);
while (n > 0) {
if (n % 2 == 1) {
ret = ret.multiply(matrix); // 算 A
}
n = n / 2;
matrix = matrix.multiply(matrix); // 算 A(^n)
}
return ret;
}
}
public static int fibonacci(int n) {
int m = n - 1;
if (m == 0) {
return 0;
}
if (m == 1) {
return 1;
}
Matrix A = new Matrix(2, 2);
Matrix B = new Matrix(2, 1);
A.value[0][0] = 1; A.value[0][1] = 1;
A.value[1][0] = 1; A.value[1][1] = 0;
B.value[0][0] = 1;
B.value[1][0] = 0;
return A.power(m - 1).multiply(B).value[0][0]; // f(n) = C(n)[0][0] = A^(n-1) B [0][0]
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
System.out.println(fibonacci(n));
}
我们将公式修改一下
f(n) = 6 * f(n-1) + 5 * f(n-2) + n^2 + 6 * n + 5
同样的, 需要先找出 矩阵 A 和矩阵 B
同样的 C = AB, 我们需要找的 f(n) = C(n)[0][0]
我们拟构造一下
当 n = 2 和 n = 3 时,
矩阵A 需要做的 就是 n = 3 时 的结果 是 n=2 时的结果 和 矩阵A 相乘
n=3时:
第一行: f(2) = 6 * f(1) + 5 * f(0) + (2+1)^2 + 6 * 2 + 5
第二行: f(1) = n为2时的第一行
第三行: (2+1) ^ 2 = 2^2 + 2*2*1 + 1^2
第四行: 2+1 = 2 + 1
第五行: 1 = 1
体现在矩阵A 中:
我们模拟一下数据:
第一个数 f(0) : 0
第二个数 f(1) : 1
第三个数 f(2) : 27
第四个数 f(3) : 199
第五个数 f(4) : 1374
......
最后我们修改一下代码来实现
我们只需要修改一下矩阵A 和矩阵B就可以了, 带入刚刚推出来的矩阵A 和矩阵B
public static int fibonacci(int n) {
int m = n - 1;
if (m == 0) {
return 0;
}
if (m == 1) {
return 1;
}
int[][] X = {
{6, 5, 1, 6, 5},
{1, 0, 0, 0, 0},
{0, 0, 1, 2, 1},
{0, 0, 0, 1, 1},
{0, 0, 0, 0, 1}
};
int[][] y = {
{1},
{0},
{4},
{2},
{1}
};
Matrix A = new Matrix(5, 5);
Matrix B = new Matrix(5, 1);
A.value = X;
B.value = y;
return A.power(m - 1).multiply(B).value[0][0];
}
其他的地方不变
测试一下
第6个数 为 f(5) = 6 * f(4) + 5 * f(3) + 5^2 + 6 * 5 + 5 = 9299
缺陷: 当第n个数过大时, 使用int类型装不下会产生溢出