什么是解决二阶问题递归关系的有效算法?

时间:2014-03-10 14:24:36

标签: algorithm recursion time-complexity recurrence

我想解决其中二次项的递归关系。

例如.. T(n)= T(n-1)^2 + T(n-1) + 2是一个递归关系,我必须打印其总和模块100000.

如果不使用简单的强力方法,我该怎么做?

3 个答案:

答案 0 :(得分:3)

取决于n的大小(例如,大约10,000,000),您可能会在一小段时间(例如大约一秒钟)内运行一个简单的for循环。

我无法判断您是否可以找到通用T(1)和/或通用递归的数学公式,但我的猜测是您不能。不过,我可以告诉你一个可以帮助你解决问题的数学属性。它被称为congruence。简而言之,这就是语法:

a =(15)= b

表示15分为b - a。实际的数学符号是=,有三行,数字写在它上面,但我不能真正输入它!

现在这里有几个对你有用的定理:

1

a =(n)= b  \
            > => a =(n)= c
b =(n)= c  /

2

a =(n)= b  =>  a+c =(n)= b+c

3

a =(n)= b  =>  a*c =(n)= b*c

4

a =(n)= b  =>  a^2 =(n)= b^2

通过将ab写为:

,可以轻松证明这些问题
a = k1*n+r
b = k2*n+r

并应用转换并确保最后b - a仍可被n整除。


那就是说,你的算法如下(假设你想要T1到TN mod M之和):

T = 3        /* initial T1 */
TSum = T     /* initial sum */

for i=1 to N
    T = (T^2 % M + T + 2) % M
    TSum = (TSum + T) % M

这里要注意的重要一点是,TTSum总是由M限定,最大中间结果来自表达式T^2(对于非平凡的M s),最多可以(M-1)^2

因此,在您的实现中,您实际上不需要处理非常大的数字,而只需要使用足以容纳(M-1)^2的数据类型。在C中,uint64_t会这样做。请注意,对于M=100000(M-1)^2不适合32位整数。

顺便说一下,这个算法是O(N),所以除非N非常大或除非它在一个非常频繁的循环中,否则它应该足够快以满足您的日常需求!


修改

问题实际上可以在O(M)而不是O(N)中解决。这是因为所有T(i)都在[0, M-1)范围内,因此计算到T(M+1),您肯定会回头。由于T(n)完全取决于T(n-1),因此获取T(n-1)的重复值将导致与第一次相同的值链。

因此,让我们展开TTSum,以便更好地了解这是如何被利用的。假设T生成值AB,...,Z,在Z之后,它会循环回K并在一对夫妇之后它在P完成的周期(因为我们达到了N):

T    A   B   C   D   E   ... K   ...  Z   K   ... Z   K   ... Z   ... K   ... P
TSum AS  BS  CS  DS  ES  ... KS  ...  ZS  KS2 ... ZS2 KS3 ... ZS3 ... KSt ... PSt

所以你的目标是计算PSt。我们的想法是计算最多KS2,将其与KS区分开来,将其乘以t并将其添加到KS以获得KSt。然后添加剩余部分以获取PSt

算法如下:

Sums=[M times 0]    /* initially, no sum is calculated */
Indices=[M times 0] /* Indices[i] = I means Sums[i] corresponds to T(1)+...+T(I) */
T = 3           /* initial T1 */
TSum = T        /* initial sum */
Sums[T] = TSum
Indices[T] = 1

for i=2 to N
    T = (T^2 % M + T + 2) % M
    if Sums[T] != 0         /* a loop is detected */
        break

    TSum = (TSum + T) % M
    Sums[T] = TSum
    Indices[T] = i

if i == N
    return TSum

/* compute how many cycles */
cycle_length = i - Indices[T]
t = (N - Indices[T]) / cycle_length

/* add sum of the cycles immediately */
TSum = (Sums[T] + t * (TSum - Sums[T])) % M

/* add what is left */
for i=Indices[T] + t * cycle_length+1 to N
    T = (T^2 % M + T + 2) % M
    TSum = (TSum + T) % M

注意:索引计算中可能存在逐个错误。如果您打算使用此算法,请仔细检查以确保它不会遗漏任何T(i)或将其加总两次。

答案 1 :(得分:2)

这是一种更加数学化的方法来解决递归方程,例如使用z变换或生成函数。对所讨论的方程进行z变换,然后找到f(z)生成多项式用于递推,并采用逆z变换得到闭合空间函数。

<强>步骤:

  1. Z - 转换 T(n)
  2. 根据 z 查找 F(z) z 是您重现的生成多项式。
  3. 反向(F(z))以获得重现的封闭式方程式。
  4. 获取封闭表格后,您可以直接从 n
  5. 中找到 T(n)
  6. 您可以进一步找到结算的封闭表格。

答案 2 :(得分:0)

这实际上更像是一个数学问题,但无论如何,这里有一些你应该考虑的事情:

  1. 如果您只对总和100,000 100,000感兴趣,则可以执行所有计算模式100,000。 (如果你不知道为什么这是真的,不要尝试在作业答案中使用它。但那当然是一个数学问题。)

  2. 你有一阶递归方程(你的标题是错的,顺便说一下),真的应该不是通过递归来实现它,而是迭代地实现它。

  3. 粗糙的伪代码(希望你能从中吸取教训,不只是把它作为功课,但是再一次,你唯一受伤的就是你自己):

    value = 3 // T(1)
    sum = value
    N.times do
      value = (value^2 + value + 2) % 100000
      sum = (sum + value) % 100000
    end
    

    对于更加面向数学的答案,您还可以考虑如何获得和S(n)的递归公式,然后为此计算闭合形式的解。