我有这个程序
//h is our N
static int g=0;
int fun(int h){
if(h<=0){
g++;
return g;
}
return g+fun(h-1)+fun(h-4);
}
是否可以使用动态编程加快速度?
我发现这个函数在O(2 ^ n)
中运行我应该通过动态编程减少运行时间,但不理解这个概念。
只是想要朝着正确的方向努力。
答案 0 :(得分:7)
虽然我无法回答你的实际问题,但我对一些完全不同的东西很感兴趣,即陈述
return g+fun(h-1)+fun(n-4);
显然,您的函数具有更改全局静态变量g
的副作用。我不是100%确定return
语句的表达式是否以明确定义的方式实际评估,或者结果是否未定义。
考虑执行这些函数调用的顺序,以及它如何影响g
从而影响函数的结果,这可能是一个很好的练习。
答案 1 :(得分:1)
如果我们定义g + fun(h-1)+ fun(n-4)中的求和顺序是从左到右,那么这是一个很好定义的问题。有了这个,我得到fun(n),n = 1,...,15:
的值3, 6, 10, 15, 33, 74, 154, 295, 575, 1143, 2269, 4414, 8508, 16396, 31634
fun(n)的返回值被评估为具有非降序元素的求和序列。每个加数比前一个更大(返回g ++;)或与之前相同(返回 g + fun()+ fun())。 return语句的执行顺序仅取决于fun()输入参数。因此,当g设置为初始值!= 0时,我们得到与g = 0相同的加数,但是对于相同的初始值,每个加数都更大。 有了它,有趣的(n)与初始g&gt; 0将返回 g *执行的返回语句数的值大于初始g = 0的值。
在执行fun(n)时将A(n)定义为执行的返回语句的数量,并在 if 子句中将执行的返回语句的G(n)编号定义为(与g ++语句执行的数量相同) 。对于A和G持有:
A(n) = A(n-1) + A(n-4) + 1
G(n) = G(n-1) + G(n-4)
A(n) = 1 and G(n) = 1, for n <= 0
从这些观察结果可以看出,对于n> 0代表:
fun(n) = fun(n-1) + G(n-1) * A(n-4) + fun(n-4)
简单的python实现:
def x( h ):
Rg = { -3:1, -2:1, -1:1, 0:1 }
Ra = { -3:1, -2:1, -1:1, 0:1 }
F = { -3:1, -2:1, -1:1, 0:1 }
for i in xrange( 1, h+1 ):
F[i] = F[i-1] + Rg[i-1]*Ra[i-4] + F[i-4]
print i, F[i]
Rg[i] = Rg[i-1] + Rg[i-4]
Ra[i] = Ra[i-1] + Ra[i-4] + 1
@stakx:对于表达式g + fun(h-1)+ fun(h-4)我们不能有评估顺序保证,特别是在C中没有。
答案 2 :(得分:0)
是的,可以使用DP加速并避免使用CPU堆栈,但我同意stakx关于更改全局静态变量g的副作用。 最好提供一个数学表达式,因为上面的递归函数可以根据顺序和顺序给出不同的结果。电话数量。
答案 3 :(得分:0)
行。我们从有趣开始(强制评估顺序的序列化版本)。
int fun(int h){
if(h<=0){
g++;
return g;
}
int tmp1 = g;
int tmp2 = fun(h-1);
int tmp3 = fun(h-4);
return tmp1+tmp2+tmp3;
}
让我们专注于g并忘记函数的当前结果
现在可以很容易地将函数更改为传入g作为参数并作为结果返回g的新值。
int gun(int h, int g0){
if(h<=0){
return g0+1;
}
int tmp1 = g0;
int tmp2 = gun(h-1, g0);
int tmp3 = gun(h-4, tmp2);
return tmp3;
}
What can be simplified into:
int gun(int h, int g0){
if(h<=0){
return g0+1;
}
return gun(h-4, gun(h-1, g0));
}
现在回到乐趣:
int fun2(int h, int g0){
if(h<=0){
return g0+1;
}
return g0+fun2(h-1, g0)+fun2(h-4, gun(h-1,g0));
}
fun2与最初的乐趣完全相同,但是现在当我们删除副作用并且函数仅取决于它的参数时,我们可以记住结果(将已计算的结果存储在数组中),这应该加速计算。
我们仍然可以简化一下枪。 g0参数不是必需的,我们将其设置为0。
int gun2(int h){
if(h<=0){
return 1;
}
return gun2(h-4) + gun2(h-1);
}
我们甚至可以定义一个fun3,其中g0参数固定为0,从而稍微简单一些,但它仍然需要调用fun2。我还没有看到如何进一步简化,但它可能是可能的。
int fun3(int h){
if(h<=0){
return 1;
}
return fun3(h-1)+fun2(h-4, gun2(h-1));
}