【问题标题】:what is an efficient algorithm for solving recurrence relation for 2nd order problems?解决二阶问题的递归关系的有效算法是什么?
【发布时间】:2014-03-11 09:47:40
【问题描述】:

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

例如..T(n)= T(n-1)^2 + T(n-1) + 2 是一个递归关系,我必须打印它的 sum mod 100000。

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

【问题讨论】:

  • 1) “打印它的sum”是什么意思?你想计算 T(n) 吗? 2) 基本情况是什么?
  • 不是总和,我的意思是 (T(1)+T(2)+...+T(N)) MOD 100000。
  • 我没有得到你的第二个问题?你是在问我最好的案例解决方案还是什么!?
  • 对于每个递归,都有一个基本情况,用于终止递归。例如:什么是 T(1)?
  • 这个问题的主题如何?这应该在数学网站上。

标签: algorithm recursion time-complexity recurrence


【解决方案1】:

根据 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(对于非平凡的Ms)可以采取最多(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) 或将其相加两次。

【讨论】:

  • 如果 n 大于 10,00,00,000 会怎样。
  • 我认为 O(log n) 是 OP 正在寻找的...我将您的方法描述为“简单的蛮力”
  • @NiklasB.,没错。这是一种简单的蛮力。然而,更简单和更慢的蛮力(虽然实际上更难实现!)将简单地计算 T 和 Tsum,无论它们有多大。我写了这个答案是因为我认为 OP 可能没有考虑过这种优化,而这种优化本可以使一个简单的蛮力变得很好。
  • 对周期长度的良好观察 :) 当您的复发取决于 k 较早的术语时,同样的原则适用,在这种情况下,您的周期长度小于 M^k
  • 我添加了一个更新来限制执行率。 @tacet,现在试着把 n 放在上面! ;)
【解决方案2】:

这是一种求解递归方程的更数学方法,例如使用 z 变换或生成函数。对所讨论的方程进行 z 变换,然后找到 f(z) 生成多项式的递归式,并进行 z 逆变换以得到封闭形式的离散空间函数。

步骤:

  1. 采用z-变换T(n)
  2. 根据 z 找到 F(z),这是您的递归生成多项式。
  3. Inverse(F(z)) 得到递归的闭式方程。
  4. 得到封闭的表格后可以直接从n中找到T(n)
  5. 您可以进一步找到总结的封闭形式。

【讨论】:

  • 您能否举例说明如何针对这种特定的重复执行此操作?这可能很有趣:)
  • @NiklasB。使用 z 变换求解递归的最好例子是斐波那契数列封闭形式的解。math.stackexchange.com/questions/279868/…
  • 这本免费书中甚至更好的例子:math.upenn.edu/~wilf/DownldGF.html ;-)
  • @fex:谢谢,我想我有一段时间遇到过这个问题,但不记得它提到过任何关于“z-transform”的内容。
  • Z 变换仅适用于线性递归,即使如此也不是所有类型的系数。另一个名字是生成函数。但是问题中递归中 T 的平方禁止使用递归。在这里最好的方法是观察 (T[n]+0.5)=(T[n-1]+0.5)^2+2.25,这对于找到封闭形式的解决方案并没有真正的帮助。
【解决方案3】:

这实际上更像是一道数学题,但无论如何,您应该考虑以下几点:

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

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

粗略的伪代码(希望你能从中吸取教训,不仅仅是把它当作家庭作业,但话又说回来,你唯一会受伤的就是你自己):

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

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

【讨论】:

  • 关键是当迭代方法太慢但无法解决递归时,你可以为大 n 做些什么
  • 一般来说,什么都没有。有一些你可以部分解决的递归,例如,对于 2^n,这会给你一个 O(log(n)) 算法(例如,参见 Knuth 关于约瑟夫斯问题的论文),但比 O(n ) 将对递归方程进行部分求解。
  • 对于像 Fibonacci、3-Fibonacci 等线性递归,其中 F(n) 是 F(n-k), ..., F(n-1) 的线性组合,有一个涉及矩阵乘法的通用解决方案方法,该方法在 O(k^3 * log n) 中运行。我认为 OP 想知道如果你有二次项是否存在类似的东西
  • @NiklasB。但是该算法转换为显式解决方案(可能涉及也可能不涉及描述多项式根的常数,这些常数不能用根式表示,但可以近似为任意精度),因为您可以给出 A^n 的显式公式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-10
  • 2016-03-09
  • 2021-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
相关资源
最近更新 更多