今日事项-2024年7月18日

今日事项-2024年7月18日

事项一 看3个实用的算法

1. 单源最短路径(Bellman-Ford Algorithm)

单源最短路径示例图片

产生原因与背景:

想象你是一名邮递员,需要从邮局出发,递送包裹到城市中的各个角落。单源最短路径算法就像你规划的路线,它帮助你找到从邮局到每个目的地的最短路径,即使有些道路可能会因为修路而暂时封闭。

算法思路:

单源最短路径算法就像是一位旅行者在探索一个未知的岛屿,他从起点出发,逐步探索每一条可能的路径,直到确定没有更短的路径可以到达目的地。

代码案列:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def bellman_ford(graph, source):
# 初始化距离数组,所有节点到源点的距离为无穷大,除了源点自身
distances = {node: float('inf') for node in graph}
distances[source] = 0

# 重复|V|-1次,其中|V|是顶点数
for _ in range(len(graph) - 1):
for node in graph:
for neighbor, weight in graph[node].items():
# 如果通过当前节点到邻居节点的距离更短,则更新距离
new_distance = distances[node] + weight
if new_distance < distances[neighbor]:
distances[neighbor] = new_distance

# 检查是否存在负权环
for node in graph:
for neighbor, weight in graph[node].items():
if distances[node] + weight < distances[neighbor]:
raise ValueError("Graph contains a negative-weight cycle")

return distances

# 使用示例
graph = {
'A': {'B': 1, 'C': 4},
'B': {'D': 3},
'C': {'D': 5, 'E': 2},
'D': {},
'E': {'D': -3}
}
source = 'A'
print("Shortest distances from", source, ":", bellman_ford(graph, source))

算法优缺点:

优点:Bellman-Ford算法能够处理图中的负权边,并且能够检测负权环。
缺点:算法的时间复杂度为O(|V| * |E|),在|E|接近|V|^2的稠密图中效率较低。

解决缺点的方法:

对于不包含负权边的图,可以使用更高效的算法,如Dijkstra算法。

解决缺点后的代码案例:

略(Dijkstra算法已经在上文中给出)

算法的3个实际应用案例:

  • 路网导航:在存在临时道路施工或通行费变更的情况下,计算最短路径。
  • 金融分析:在金融市场中,评估不同投资组合的风险和回报。
  • 供应链优化:在存在多种运输成本和时间的情况下,找到成本最低的运输路径。

2. 长路径问题(Longest Path Problem)

产生原因与背景:

想象你是一名探险家,正在探索一个未知的森林,你需要找到一条最长的路径,以便尽可能多地探索森林的每一个角落。长路径问题就像你的探险地图,帮你找到森林中最长的路径。

算法思路:

长路径问题就像是一位旅行者在规划他的旅程,他需要考虑所有可能的路线,并选择一条能够覆盖最远距离的路线。

代码案列:

略(长路径问题的实现较为复杂,通常涉及图的遍历)

算法优缺点:

优点:长路径问题在某些应用中非常有用,如在网络设计中找到最长的通信路径。
缺点:长路径问题在某些图中可能非常难以解决,特别是图中存在很多环和交叉路径时。

解决缺点的方法:

可以通过使用动态规划或图的拓扑排序来解决长路径问题,这些方法可以避免在环中无限循环。

解决缺点后的代码案例:

略(实现通常需要特定的图结构和算法)

算法的3个实际应用案例:

  • 网络设计:在设计通信网络时,找到最长的通信路径。
  • 物流规划:在物流配送中,规划最长的配送路线以覆盖更多的客户。
  • 游戏设计:在游戏关卡设计中,找到最长的探索路径以增加游戏的挑战性。

3. 斐波那契数列(Fibonacci Sequence)

斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)

产生原因与背景:

想象你是一名生物学家,正在研究兔子的繁殖问题。斐波那契数列描述了一对兔子每个月繁殖的后代数量,每个月新生的兔子下个月开始繁殖,直到无穷。

算法思路:

斐波那契数列就像是一位园丁在计算植物的生长,每一代植物的数量是前两代植物数量的和。

代码案列:

1
2
3
4
5
6
7
8
9
10
11
def fibonacci(n):
if n <= 1:
return n
a, b = 0, 1
for _ in range(2, n + 1):
a, b = b, a + b
return b

# 使用示例
n = 10
print("The 10th Fibonacci number is:", fibonacci(n))

算法优缺点:

优点:斐波那契数列的递归实现非常直观,易于理解。
缺点:递归实现在计算大的n时效率较低,因为有很多重复计算。

解决缺点的方法:

使用动态规划方法,通过存储已经计算过的斐波那契数来避免重复计算。

解决缺点后的代码案例:

1
2
3
4
5
6
7
8
9
10
11
def fibonacci_dp(n):
if n <= 1:
return n
fib_numbers = [0, 1] + [0] * (n - 1)
for i in range(2, n + 1):
fib_numbers[i] = fib_numbers[i - 1] + fib_numbers[i - 2]
return fib_numbers[n]

# 使用示例
n = 10
print("The 10th Fibonacci number is:", fibonacci_dp(n))

算法的3个实际应用案例:

  • 计算机算法竞赛:在解决优化问题时,经常需要计算斐波那契数列。
  • 金融数学:在某些金融模型中,斐波那契数列用于预测市场趋势。
  • 生物信息学:在DNA序列分析中,斐波那契数列用于描述某些生物过程。

事项二 吃透 快速幂算法

通过一个具体的例子来演示这个快速幂算法的代码是如何工作的。假设我们要计算[2^{10}]。

代码:

1
2
3
4
5
6
7
8
9
10
11
long long Fast_Pow(long long a, long long b) {
long long result = 1; /* 初始化结果为1 */
while (b) {
if (b & 1) { /* 判断b是否为奇数 */
result *= a; /* 如果b是奇数,将a乘以当前的结果 */
}
a *= a; /* a的值是其自身的平方 */
b >>= 1; /* 将b右移一位,相当于b = b / 2 */
}
return result; /* 返回计算结果 */
}

计算过程:

  1. 初始状态

    • ( a = 2 )
    • ( b = 10 )
    • ( result = 1 )
  2. 第一次循环

    • ( b = 10 )(二进制为1010)
    • ( b & 1 = 0 )(不是奇数,不执行乘法)
    • ( a = 2 * 2 = 4 )
    • ( b = 10 )右移一位 = ( 5 )(二进制为101)
  3. 第二次循环

    • ( b = 5 )(二进制为101)
    • ( b & 1 = 1 )(是奇数,执行乘法)
    • ( result = 1 * 4 = 4 )
    • ( a = 4 * 4 = 16 )
    • ( b = 5 )右移一位 = ( 2 )(二进制为10)
  4. 第三次循环

    • ( b = 2 )(二进制为10)
    • ( b & 1 = 0 )(不是奇数,不执行乘法)
    • ( a = 16 * 16 = 256 )
    • ( b = 2 )右移一位 = ( 1 )(二进制为1)
  5. 第四次循环

    • ( b = 1 )(二进制为1)
    • ( b & 1 = 1 )(是奇数,执行乘法)
    • ( result = 4 * 256 = 1024 )
    • ( a = 256 * 256 )(这一步在循环结束后执行,不影响结果)
    • ( b = 1 )右移一位 = ( 0 )(循环结束)

最终结果:

  • ( result = 1024 ),这就是[2^{10}]的结果。

通过这种方式,快速幂算法有效地减少了乘法的次数,从而提高了计算的效率。

涉及到的知识点

这段代码中涉及到的语法知识点主要包括以下几点:

  1. 函数定义

    • 使用def关键字定义函数。
    • 函数名Fast_Pow,参数列表(long long a, long long b)
  2. 数据类型

    • long long:在C/C++中,long long是一种64位整数类型,用于存储大整数。
  3. 变量声明与初始化

    • long long result = 1;:声明并初始化一个long long类型的变量result,初始值为1。
  4. 循环结构

    • while (b):一个无限循环,条件是b非零。当b为零时,循环结束。
  5. 位运算

    • b & 1:位与运算,用于判断b的最后一位是否为1,即判断b是否为奇数。
    • b >>= 1:位右移运算,将b的二进制表示向右移动一位,相当于将b除以2。
  6. 条件判断

    • if语句:用于条件判断。如果条件为真,则执行if块内的代码。
  7. 乘法运算

    • result *= a;:乘法赋值运算符,相当于result = result * a;
  8. 赋值运算

    • a *= a;:赋值运算符,用于将a的平方赋值给a
  9. 递归调用

    • 尽管这段代码本身不是递归实现的,但快速幂算法的递归实现会涉及递归调用,即函数调用自身。
  10. 返回值

    • return result;:结束函数,并将结果返回给调用者。
  11. 注释

    • 使用/**/进行多行注释,或者使用//进行单行注释。

这些知识点是理解和实现快速幂算法的基础,也是C/C++编程中常用的语法和概念。


今日事项-2024年7月18日
http://example.com/2024/07/18/今日事项-2024年7月18日/
Beitragsautor
XiangHui
Veröffentlicht am
July 18, 2024
Urheberrechtshinweis