有没有办法减少时间复杂度,找到这个矩阵的功率n?

时间:2012-09-04 17:50:58

标签: c++ algorithm

我正在解决一个问题,我应该找到nth矩阵的4x4幂,其中n可以与10^15一样大,并且因为答案中的值可以非常大我可以使用modulo 10^9+7。 鉴于Matrix是 -

   2  1 -2 -1
A= 1  0  0  0
   0  1  0  0
   0  0  1  0 

我为此目的编写了代码,但其运行时间超过了预期的时间。所以 有人请帮我减少时间复杂度。

#define FOR(k,a,b) for(typeof(a) k=(a); k < (b); ++k)
typedef long long ll;
#define dim 4
struct matrix {
    long long a[dim][dim];
};
#define MOD 1000000007
matrix mul(matrix x, matrix y)
{
    matrix res;
    FOR(a, 0, dim) FOR(b, 0, dim) res.a[a][b] = 0;
    FOR(a, 0, dim) FOR(b, 0, dim) FOR(c, 0, dim) {
    ll temp = x.a[a][b] * y.a[b][c];
    if (temp <= -MOD || temp >= MOD)
        temp %= MOD;
    res.a[a][c] += temp;
    if (res.a[a][c] <= -MOD || res.a[a][c] >= MOD)
        res.a[a][c] %= MOD;
    }
    return res;
}

matrix power(matrix m, ll n)
{
    if (n == 1)
        return m;
    matrix u = mul(m, m);
    u = power(u, n / 2);
    if (n & 1)
        u = mul(u, m);
    return u;
}

matrix M, RP;
int main()
{
    FOR(a, 0, dim) FOR(b, 0, dim) M.a[a][b] = 0;
    M.a[0][0] = 2;
    M.a[0][1] = 1;
    M.a[0][2] = -2;
    M.a[0][3] = -1;
    M.a[1][0] = 1;
    M.a[2][1] = 1;
    M.a[3][2] = 1;
    int nt;
    scanf("%d", &nt);
    while (nt--) {
    ll n;
    scanf("%lld", &n);
    RP = power(M, n);
    FOR(a, 0, dim)
        FOR(b, 0, dim)
        printf("%lld\n", RP.a[a][b]);
    }
    return 0;
}

3 个答案:

答案 0 :(得分:2)

[评论者表示这个答案是不完整的。答案保留在这里以供参考,但不想再投票。评论者是否会根据自己的判断添加更完整的答案?]

是。一个很好的方法来做你想要的事情是众所周知的。你必须对角化矩阵。

对角化需要一些编程。在教派中解释了here,的理论。 14.6。 幸运的是,像LAPACK这样的现有矩阵代数库已经包含了对角化例程。

@Haile正确且有趣地观察到并非所有矩阵都是可对角化的,存在退化情况。我对这些案件没有多少实际经验。存在Schur分解(参见先前链接源的第14.10节),但我通常看到Schur仅用于制作理论点,而不是用于实际计算。不过,我相信舒尔会工作。我怀疑,实施它需要付出很多努力,但即使在严格不可对角化的矩阵的情况下,它也会起作用。

答案 1 :(得分:2)

您可以利用多个测试用例来减少总计算量。

请注意,每次拨打电源时,您都会重新计算原始矩阵2的所有幂。因此,对于像10 ^ 15(大约2 ^ 50)这样的数字,您将最终将矩阵平方50次,并且还计算该数字中每个非零位的乘数(可能是25次)。

如果你只是预先计算2的50次幂,那么每个测试用例只需要平均25次乘法而不是75次。

您可以进一步采用这个想法,并使用不同的基数进行求幂。这将导致更多的预计算,但每个测试值的最终矩阵乘法更少。

例如,您可以预先计算[M ^ 1,M ^ 2,M ^ 3],[M ^ 4,M ^ 8,而不是预先计算M ^ 2,M ^ 4,M ^ 8,M ^ 16, M ^ 12],[M ^ 16,M ^ 32,M ^ 48]等M ^ 51将是(M ^ 3)*(M ^ 48)而不是M * M ^ 2 * M ^ 16 * M ^ 32

答案 2 :(得分:0)

这不是一个关于更快地对指标进行取幂的想法,而是关于加速整个程序的想法。

如果要求您执行10 ^ 4个指数,这并不意味着它们应该独立完成。您可以对请求进行排序,并为每次下一次计算重复使用先前的结果。

您还可以存储先前计算的中间结果。