【发布时间】:2021-06-30 00:51:12
【问题描述】:
我正在尝试编写(我认为是一段漂亮的代码)一个 Java 程序,该程序将通过以下方式通过有效的矩阵求幂找到递归定义序列的 n'th 项:
Given 是一个线性递归关系:
f(n) = c_1 * f(n-1) + c_2 * f(n-2)+ ... + c_k * f(n-k) = sum_{i=1}^k c_i * f(n-i)
已知整数系数C_k = c_{1<=i<=k} 和已知整数基本情况B_k = b_{1<=i<=k}
为了演示符号,对于众所周知的斐波那契数列,这变为C_2 = {1,1} 和基本情况B_2 = {1,1}、f(n) = f(n-1) + f(n-2)。
Java 方法将所需的术语索引n、mod m(因为术语增长得非常快)、系数数组C_k 和基本情况数组B_k 作为参数。该方法返回值f(n) mod m。
类如下所示:
public class test2 {
public static void main(String[] args)
{
long n = 13;
long m = 100000000L;
long [] baseCases = {1,1};
long [] coefficients = {1,1};
long v = f(n , m , coefficients , baseCases);
System.out.println(v);
}
public static long f (long n , long m , long [] coefficients , long [] baseCases) //main method, taking arguments of nth term, mod m , coefficients and base cases
{
// generate the transformation matrix {c1, c2 , c3} , {1,0,0...} , {0,1,0,0...} , {0,0,1,0....}........
int k = coefficients.length;
long [][] M = new long [k][k];
for (int i = 0 ; i < k ; i++)
M[0][i] = coefficients[i];
for (int i = 1 ; i < k ; i++)
{
for (int j = 0 ; j < k ; j++)
M[i][j] = 0;
M[i][i - 1] = 1;
}
// generate the "bases" matrix
long [][] B = new long [baseCases.length][baseCases.length];
for (int i = 0 ; i < baseCases.length ; i++)
B[0][i] = baseCases[i];
for (int i = 1 ; i < B.length ; i++)
for (int j = 0 ; j < B[0].length ; j ++)
B[i][j] = 0;
long v = ME(B , M , n - k + 1 , m); //the matrix raised to the n-k+1 power would yield the nth term. for fibonacci, k = 2 , so n-1 exponentioation
return v;
}
public static void mult (long M1 [][] , long M2 [][] , long m) //method to multiply 2 matrices
{
int r = Math.max(M1.length, M2.length);
int c = Math.max(M1[0].length, M2[0].length);
int mulTemp[][] = new int[r][c]; //temporary matrix to store values
for (int i = 0 ; i < r ; i++)
{
for (int j = 0 ; j < c ; j++)
{
mulTemp[i][j] = 0;
for (int k = 0 ; k < r ; k++)
mulTemp[i][j] += M1[i][k] * M2[k][j] % m;
}
}
//transferring the values back to M1
for (int i = 0 ; i < M1.length ; i++)
for (int j = 0 ; j < M1[0].length ; j++)
M1[i][j] = mulTemp[i][j];
}
public static long ME (long B[][] , long M[][] , long n , long m) //method for fast matrix exponentiation
{
if (n == 1)
{
long s = 0;
for (int i = 0 ; i < B[0].length ; i++)
s += B[0][i];
return s;
}
ME(B , M , n / 2 , m);
mult(M , M , m);
if ((n & 1) != 0)
mult(B , M , m);
long s = 0;
for (int i = 0 ; i < B[0].length ; i++)
s += B[0][i];
return s;
}
}
代码相对简洁明了,并根据需要进行了注释,但并没有达到预期的效果。例如,正如当前在 main 方法中编写的那样,我正在尝试用它生成斐波那契数列。斐波那契数确实生成了,但不是用各自的n 生成的(对于n=13,它给出5,它应该给出233,对于n=10,它给出89 而不是55)。
我认为我对矩阵方法的处理不当,而且我没有正确使用基本情况,我不确切知道如何在代码中使用它们。我认为我转换基本情况的方式有问题将cases数组放入B矩阵中。如果我正确理解理论,则转换矩阵的形式为:
c1 , c2 , c3 , c4....
1 , 0 , 0 , 0 ....
0 , 1 , 0 , 0 ....
0 , 0 , 1 , 0 ....
......................
............... 1 , 0
从那里开始,这是一个矩阵求幂的问题,使用中间的基本情况矩阵。
我想知道如何更改此代码以能够处理任何线性递推关系,使用我提到的已知给定(整数)参数,而不仅仅是斐波那契数列(我只在帖子,因为它是最容易理解和实施的)。我可以轻松查找 Fibonacci 矩阵求幂算法,但它并没有让我深入了解如何在算法中推广这个想法,尽管我认为数学很清楚。
我真正要问的是如何在代码中实现这个理论。
【问题讨论】:
标签: java algorithm recursion matrix matrix-multiplication