题目就是这样的,原题中是扩展的Fibonacci数列,但是为了简化问题,我就把题目中的X,Y都置1了。简单的说就是取一个Fibonacci数列,两个数相乘,左边那个从F0取到Fn,右边那个从Fn取到F0(图片中的F0*F1应改为F0*Fn)。不能使用数组和递归,说实话,用递归怎么解决我也还没思考过。
首先我自己写了个程序,没想到的是和作者的解法完全不一样。其实我的想法还是比较简单的Fibonacci的递推式是Fn=Fn-1+Fn-2,那么在知道Fn和Fn-1的情况下就可以通过Fn-2=Fn-Fn-1求得Fn-2.从题目中的形式来看是从数列的两边取数,然后往中间逼近。现在逆向思维一下,如果我之前已经知道数列中间的几个数字,我同样可以往两边递推。所以在程序开始的时候,我先要求得F(n/2)然后给往左递推的两个数字赋值,和往右递推的两个数字赋值。这时数列中数字的个数是奇和偶的情况可能要做些微的调整。此时我已经能够分别从数列的左侧和右侧得到对应的数字了,那么问题也就可以解决了。具体的一些细节请参见源代码吧。
unsigned long EX_FIB(unsigned long n)
{
unsigned long F1=1,F2=1,temp,F3,F4,ans=0;
int i;
for(i=1;i<n/2;i++) //找到数列的中间的那个数
{
temp=F2;
F2=F1+F2;
F1=temp;
}
if(n&0x01) //若为奇数
{
F3=F1+F2;
F4=F2+F3;
ans=F3*F2*2+F1*F4*2;
for(i=0;i<n/2-1;i++)//从中间向两边扩展数列,保存至F2
{
temp=F1;
F1=F2-F1;
F2=temp;
temp=F4;
F4=F3+F4;
F3=temp;
ans+=F4*F1*2;
}
return ans;
}
else
{
ans=F2*F2;
F3=F1+F2;
F4=F3+F2;
temp=F1;
F1=F2-F1;
F2=temp;
ans+=F1*F4*2+F2*F3*2;
for(i=0;i<n/2-2;i++)
{
temp=F1;
F1=F2-F1;
F2=temp;
temp=F4;
F4=F3+F4;
F3=temp;
ans+=F4*F1*2;
}
return ans;
}
}
但是之后看作者的解答之后,发现他的解法和我完全不同。当然还是依旧比我简洁很多很多。作者的想法其实有点类似于递归,将有n个数字的式子看成一个整体,然后在由n+1个数字的序列的时候利用之前的式子。当然,其中用到了一些数学的推算,使式子更易于用程序语言来编写,下面就贴上推导过程吧~
其实最终得到的式子就是An+1=(An-1)+An+Fn+(Fn+1),在写程序中只要保存An-1和An,Fn+Fn+1,并且随着n的增大,不断更新即可。其中用到的核心思想我觉得还是递归吧,由已经得到的小规模问题的解得出更大规模的问题的解,不断重复达到目标。这也是计算机最擅长做的