首页 > 编程语言 >【算法】斐波那契数列与台风的故事

【算法】斐波那契数列与台风的故事

时间:2023-09-05 11:56:29浏览次数:41  
标签:BigInteger 数列 fibs 斐波 那契 台风 苏菲

在小岛的一个海滨小镇上,住着一个名叫苏菲的女孩。苏菲一家人靠海为生,她的生活简单而朴素,与大自然和谐共生。每天,苏菲都会来到海边,欣赏那美丽的日出和日落,感受着大海的呼吸。

然而,小岛的美丽风光并非一成不变。每年夏季,热带气旋活跃,台风频繁登陆,给小岛带来了严重的危害。

有一天,苏菲经历了一场猛烈的台风。台风带来的狂风暴雨席卷了整个小镇,树木被连根拔起,房屋倒塌,街道一片狼藉。苏菲的家也被摧毁了,她无家可归,生活陷入了困境。

在台风的影响下,苏菲失去了亲人,她感到孤独和无助。然而,她并没有放弃,她决定勇敢面对生活的挑战。

在台风过后,苏菲积极参与灾后重建工作,帮助邻居们重建家园。她用自己的双手清理废墟、种植树木,为小镇重新带来了生机。

在成长过程中,她遇到了一个气象专家,教会她一些数学知识。她决定要用自己的知识和力量去保护家园,减少自然灾害带来的损失。

她对斐波那契数列有着浓厚的兴趣,在闲暇时会用海滩上的贝壳摆出斐波那契数列的形状。

有一天,苏菲注意到一个有趣的现象:台风的路径似乎与斐波那契数列有关。她开始研究台风的形成和运动原理,发现台风的生命周期与斐波那契数列的规律有着奇妙的联系。

为了更准确地预测台风,苏菲需要处理大量的数据,进行复杂的计算。然而,她意识到传统的计算方法效率低下,无法满足实时预测的需求。于是,她开始寻找更高效的计算方法。

在一次数学课程中,苏菲学到了矩阵乘法的知识,她突然想到可以利用矩阵乘法来降低计算复杂度。她将台风的数据整理成矩阵形式,并利用矩阵乘法的快速幂算法来计算台风的运动轨迹和强度变化。

通过实践,苏菲发现利用矩阵乘法快速幂算法可以将计算复杂度降低到原来的十分之一以下,大大提高了计算效率。她将这种方法应用于台风预测模型中,取得了显著的成果。

苏菲将她的发现告诉了她的老师,得到了赞赏和支持。气象学家们将苏菲的方法应用于更广泛的天气预测中,取得了良好的效果。利用这一发现,政府可以提前做好防灾减灾的准备,减少台风带来的损失。

斐波那契数列的递推公式为:F(n) = F(n-1) + F(n-2),其中F(1) = 1,F(2) = 1。
以10为例,斐波那契数列的前10项为:
2 3 5 8 13 21 34 55

苏菲面临一个问题,当n=2000000的时候,就算用超级计算机来计算也会超时,等运算完毕,台风已经消失了,怎么处理这个问题呢?


算法实现:

 1 public static BigInteger fib(int n)
 2 {
 3     Console.WriteLine(n);  // 打印输入的参数n,用于调试
 4 
 5     BigInteger semn = 1;  // 定义一个BigInteger类型的变量semn,用于存储符号
 6     BigInteger t = 0;  // 定义BigInteger类型的变量t,用于临时存储中间计算结果
 7     BigInteger i = 1;  // 定义BigInteger类型的变量i,初始化为1
 8     BigInteger j = 0;  // 定义BigInteger类型的变量j,初始化为0
 9     BigInteger k = 0;  // 定义BigInteger类型的变量k,初始化为0
10     BigInteger h = 1;  // 定义BigInteger类型的变量h,初始化为1
11 
12     if (n < 0)  // 如果n小于0,表示需要计算负数的斐波那契数
13     {
14         n *= -1;  // 将n取绝对值
15         semn = n % 2 == 0 ? -1 : 1;  // 判断n的绝对值是否为偶数,如果是偶数,semn为-1,否则为1
16     }
17 
18     while (n > 0)  // 当n大于0时,进行循环计算斐波那契数
19     {
20         if (n % 2 != 0)  // 如果n是奇数
21         {
22             t = j * h;  // 计算j乘以h的结果,并赋值给t
23             j = i * h + j * k + t;  // 更新j的值,根据斐波那契数列的递推公式计算
24             i = i * k + t;  // 更新i的值,根据斐波那契数列的递推公式计算
25         }
26         t = h * h;  // 计算h的平方,并赋值给t
27         h = 2 * k * h + t;  // 更新h的值,根据斐波那契数列的递推公式计算
28         k = k * k + t;  // 更新k的值,根据斐波那契数列的递推公式计算
29         n = n / 2;  // 将n除以2,用于控制循环次数
30     }
31 
32     return j * semn;  // 返回计算得到的斐波那契数乘以符号semn,得到最终结果
33 }

这段代码使用了数论中的快速幂算法来计算斐波那契数,通过减少循环次数来降低计算量。让我们以n=2000000为例来解释算法的步骤。

首先,我们初始化变量i、j、h和k的值为0、1、1和0。然后,我们进入循环,当n大于0时,进行迭代计算。

在第一次迭代中,由于n=2000000是一个偶数,我们只需要更新h和k的值。我们计算h的平方并将结果存储在t中,然后更新h的值为2*k*h + t,更新k的值为k*k + t。此时,n被除以2,变为1000000。

在第二次迭代中,由于n仍然是一个偶数,我们再次只需要更新h和k的值。我们计算h的平方并将结果存储在t中,然后更新h的值为2*k*h + t,更新k的值为k*k + t。此时,n被除以2,变为500000。

依此类推,我们继续进行迭代,每次将n除以2,直到n变为1。在这个过程中,我们只需要更新h和k的值,而不需要更新i和j的值。

当n变为1时,我们进行最后一次迭代。由于n是奇数,我们需要更新i和j的值。我们计算j*h的结果并将其存储在t中,然后更新j的值为i*h + j*k + t,更新i的值为i*k + t。

最后,当n变为0时,循环终止。此时,i的值就是斐波那契数列中第2000000个数的值。

通过使用快速幂算法,我们只需要进行log(n)次循环,而不是n次循环,从而大大降低了计算量。在这个例子中,由于n=2000000,我们只需要进行log(2000000) ≈ 21次循环,而不是2000000次循环,从而提高了计算效率。


 

测试用例:

 1 using NUnit.Framework;
 2 using System;
 3 using System.Collections.Generic;
 4 using System.Numerics;
 5 
 6 public class FibonacciTest
 7 {
 8 
 9     [Test]
10     public void testFib()
11     {
12         List<int> tests = new List<int> { 0, 1, 2, 3, 4, 5, -6, -96, 1000, 1001 };
13 
14         Random rnd = new Random();
15         for (int i = 0; i < 10; ++i)
16         {
17             tests.Add(rnd.Next(-100, 0));
18         }
19         tests.Add(rnd.Next(10000, 100000));
20         tests.Add(rnd.Next(1000000, 1500000));
21 
22         foreach (int n in tests)
23         {
24             BigInteger found = Fibonacci.fib(n);
25             Assert.AreEqual(FibonacciRef.fib(n), found);
26         }
27     }
28     
29     private static class FibonacciRef
30     {
31         private static IDictionary<int, BigInteger> fibs = new Dictionary<int, BigInteger>();
32 
33         static FibonacciRef()
34         {
35             fibs[0] = BigInteger.Zero;
36             fibs[1] = BigInteger.One;
37             fibs[2] = BigInteger.One;
38             fibs[3] = fibs[2] + fibs[1];
39             fibs[4] = fibs[3] + fibs[2];
40             fibs[5] = fibs[4] + fibs[3];
41         }
42 
43         private static BigInteger calcFib(int n)
44         {
45             BigInteger result;
46             if (fibs.TryGetValue(n, out result))
47                 return result;
48 
49             if ((n & 1) == 1)
50             {
51 
52                 int k = (n + 1) / 2;
53                 BigInteger fk = BigInteger.Pow(calcFib(k), 2);
54                 BigInteger fkm1 = BigInteger.Pow(calcFib(k - 1), 2);
55                 result = fk + fkm1;
56             }
57             else
58             {
59                 int k = n / 2;
60                 BigInteger fk = calcFib(k);
61                 BigInteger fkm1 = calcFib(k - 1);
62                 result = (fkm1 * fibs[3] + fk) * fk;
63             }
64 
65             fibs[n] = result;
66             return result;
67         }
68 
69         public static BigInteger fib(int n)
70         {
71             bool neg = n < 0;
72 
73             if (neg)
74                 n = -n;
75 
76             BigInteger result = calcFib(n);
77 
78             if (neg && (n & 1) == 0)
79                 result = -result;
80 
81             return result;
82         }
83     }
84 }

 

标签:BigInteger,数列,fibs,斐波,那契,台风,苏菲
From: https://www.cnblogs.com/lan80/p/17679236.html

相关文章

  • 通过c语言来实现斐波那契数列
    斐波那契数列是一组第一位和第二位为1,从第三位开始,后一位是前两位和的一组递增数列,像这样的:0、1、1、2、3、5、8、13、21、34、55......这个数列从第3项开始,每一项都等于前两项之和。以下通过c语言来实现这个程序#include<stdio.h>//1123581321345589intmain(){ /......
  • P5175 数列
    Updated2023.07.05修正了一处笔误,在此感谢@DWT8125题解首先先推一下柿子,因为数据范围很大,所以考虑矩阵加速递推。根据题意给的递推式,可得:\[\begin{aligned}a_i^2 &=(x\timesa_{i-1}+y\timesa_{i-2})^2\\ &=x^2\timesa_{i-1}^2+y^2\timesa_{i-2}^2+2xy\timesa_{......
  • §3. 数列极限存在的条件
    掌握单调有界原理、致密性定理、柯西收敛准则,能够运用这些定理证明一个数列是否收敛。 设S为有界数集,则若,则存在严格递减数列,使得数列发散的充要条件是:存在,对任意的正整数N,总存在,使得重点习题:1、3(单调有界原理)、5-8.......
  • 剑指 Offer 10- I. 斐波那契数列(简单)
    题目:classSolution{//动态规划public:intfib(intn){if(n<=1)returnn;vector<int>dp(2,0);//确定dp数组以及下标的含义dp[0]=0;//dp数组初始化dp[1]=1;for(inti=2;i<=n;i++){//递推顺序从......
  • §1. 数列极限概念
    1. 掌握数列极限的定义,并会用语言证明给定数列的极限。如何用语言证明 :任给,研究,通过放缩得到一个比较简单的形式,然后分析得到n满足什么条件,能够使得.最后用语言总结:对任给的,只要取,则当时,.注意:N不一定限于正整数,只要是正数即可。2.掌握数列极限的几何意义和由此产生的新的定义......
  • §2. 收敛数列的性质
    1.掌握收敛数列的唯一性,有界性,保号性,保不等式性,迫敛性,四则运算。2.熟悉子列的定义以及子列极限和原数列极限的关系。当一个数列有一个子列发散,或有两个子列收敛但极限不相等,则数列一定发散。 重点习题:第1、2、4、6题,通过这些习题熟悉收敛数列性质的应用。 ......
  • 一种基于Common Lisp的用lambda从头构建逻辑、整数、算数、斐波拉契的方案
    绪论本文参考视频教程,教程给出了一系列编程题目。该教程作者裘香莲已经基于JavaScript,用lambda运算从头构建了一系列编程基础概念。本文则对其编程题以CommonLisp语言另外给出答案。逻辑与判断的实现代码展示(defparameter*t*(lambda(opt1opt2)`,opt2(funcallop......
  • 【剑指Offer】7、斐波那契数列
    【剑指Offer】7、斐波那契数列题目描述:大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。假设n<=39。解题思路:斐波那契数列:0,1,1,2,3,5,8........总结起来就是:第一项是0,第二项是1,后续第n项为第n-1项和第n-2项之和。用公式描述如下:......
  • 动态规划--斐波那契数列
    博客地址:https://www.cnblogs.com/zylyehuo/#-*-coding:utf-8-*-#子问题的重复计算--递归方法--执行效率低deffibnacci(n):ifn==1orn==2:return1else:returnfibnacci(n-1)+fibnacci(n-2)#print(fibnacci(100))......
  • 四种解决”Arg list too long”参数列表过长的办法
    在linux中删除大量文件时,直接用rm会出现:-bash:/bin/rm:参数列表过长,的错误。这时可以用find命令来结合使用。例:1、rm*-rf改为:find.-name"*"|xargsrm-rf'*'就行了。2、rmtest*-rf改为:find.-name"test*"|xargsrm-rf"test*"mv时报参数列表过长,foriin*.m......