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

算法,数列,台风,故事 · 浏览次数 : 329

小编点评

测试用例: 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 tests = new List { 0, 1, 2, 3, 4, 5, -6, -96, 1000, 1001 }; 13 Random rnd = new Random(); 15 for (int i = 0; i < 10; ++i) {17 tests.Add(rnd.Next(-100, 0)); 18 } 19 tests.Add(rnd.Next(10000, 100000)); 20 tests.Add(rnd.Next(1000000, 1500000)); 21 foreach (int n in tests) {24 BigInteger found = Fibonacci.fib(n); 25 Assert.AreEqual(FibonacciRef.fib(n), found); 26 } 27 } 28 29 private static class FibonacciRef30 { 31 private static IDictionary fibs = new Dictionary(); 32 static FibonacciRef() { 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 private static BigInteger calcFib(int n) { 45 BigInteger result; 46 if (fibs.TryGetValue(n, out result)) { 47 return result; 48 } 49 if ((n & 1) == 1) { 50 int k = (n + 1) / 2; 51 BigInteger fk = BigInteger.Pow(calcFib(k), 2); 52 BigInteger fkm1 = BigInteger.Pow(calcFib(k - 1), 2); 53 result = fk + fkm1; 54 } 55 else { 56 int k = n / 2; 57 BigInteger fk = calcFib(k); 58 BigInteger fkm1 = calcFib(k - 1); 59 result = (fkm1 * fibs[3] + fk) * fk; 60 } 61 fibs[n] = result; 62 return result; 63 } 64 return result; 65 } 66 public static BigInteger fib(int n) { 67 bool neg = n < 0; 68 if (neg) { 69 n = -n; 70 } 71 if (neg && (n & 1) == 0) { 72 return -Fibonacci.fib(n); 73 } 74 return Fibonacci.fib(n); 75 } 76 return Fibonacci.fib(n); 77 } 78 } 79 } 

正文

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

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

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

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

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

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

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

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

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

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

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

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

斐波那契数列的递推公式为: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 }

 

与【算法】斐波那契数列与台风的故事相似的内容:

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

在小岛的一个海滨小镇上,住着一个名叫苏菲的女孩。苏菲一家人靠海为生,她的生活简单而朴素,与大自然和谐共生。每天,苏菲都会来到海边,欣赏那美丽的日出和日落,感受着大海的呼吸。 然而,小岛的美丽风光并非一成不变。每年夏季,热带气旋活跃,台风频繁登陆,给小岛带来了严重的危害。 有一天,苏菲经历了一场猛烈的

应届生必考的斐波那契数列 优化版本

- 开题引入斐波那契 - 代码演示: 递归、循环 - 递归 vs 循环 - 时间复杂复高,指数型O(2^n); 推导过程 - 占用线程堆栈, 可能导致栈满异常 - 压测演示 - 20230816补充尾递归 ## 斐波那契数列 打入门软件开发,斐波那契数列便是绕不过去的简单编程算法。 一个老生常谈的思

一种基于光电容积波的血压测量神经网络算法,开源、低功耗、低成本的人工智能软硬件提供者

具体的软硬件实现点击 http://mcu-ai.com/ MCU-AI技术网页_MCU-AI人工智能 心血管疾病是最严重的死亡原因之一,每年在全世界造成严重的生命损失。持续监测血压似乎是最可行的选择,但这需要一个侵入性的过程,带来了几层复杂性。这促使我们开发一种方法,通过使用光体积描记图(PPG)

使用策略模式优化你的代码

策略模式简介 策略模式(Strategy Pattern:Define a family of algorithms,encapsulate each one,and make them interchangeable.)中文解释为:定义一组算法,然后将这些算法封装起来,以便它们之间可以互换,属于一

OI-Wiki 学习笔记

算法基础 \(\text{Update: 2024 - 07 - 22}\) 复杂度 定义 衡量一个算法的快慢,一定要考虑数据规模的大小。 一般来说,数据规模越大,算法的用时就越长。 而在算法竞赛中,我们衡量一个算法的效率时,最重要的不是看它在某个数据规模下的用时,而是看它的用时随数据规模而增长的趋

算法金 | 这绝对是不一样的,独一无二的逻辑回归算法体验

大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 今日 220+/10000 在 回归求助 & 送教程这篇文章中,我放出来最近在做的揭榜挂帅的 PPT 初稿,很多读者表示感兴趣,还有小伙伴问啥时候出书,更有同学贴心的给对象要了份PPT(

算法金 | 秒懂 AI - 深度学习五大模型:RNN、CNN、Transformer、BERT、GPT 简介

1. RNN(Recurrent Neural Network) 时间轴 1986年,RNN 模型首次由 David Rumelhart 等人提出,旨在处理序列数据。 关键技术 循环结构 序列处理 长短时记忆网络(LSTM)和门控循环单元(GRU) 核心原理 RNN 通过循环结构让网络记住以前的输入

算法金 | 深度学习图像增强方法总结

图像增强方法在数字图像处理中占有重要地位,它能够有效提高图像的视觉效果,增强图像的细节信息,从而在医学、遥感、工业检测等多个领域发挥重要作用 1. 空间域增强方法 空间域增强方法是通过直接对图像像素进行操作来实现图像增强的技术。以下是几种常见的空间域增强方法: 1.1 直方图均衡化 直方图均衡化是一

算法金 | 来了,pandas 2.0

大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 今日 210+/10000,内含 Pandas 是一个强大的数据分析库,广泛应用于科学研究、金融分析、商业智能等领域。它提供了高效的数据结构和数据分析工具,使得处理和分析数据变得更加简单

算法金 | DL 骚操作扫盲,神经网络设计与选择、参数初始化与优化、学习率调整与正则化、Loss Function、Bad Gradient

大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 今日 216/10000 抱个拳,送个礼 神经网络设计与选择 参数初始化与优化 学习率调整与正则化 数据预处理与标准化 训练过程与监控 特定模型技巧 其他训练技巧 1. 神经网络设计与选