Engee 文档
Notebook

Julia语言中的加性链算法

在这个例子中,我们考虑实现一个算法,用于在Julia编程语言中找到给定数字的加性链的最小长度。

导言

加性链算法解决了找到获得目标数所需的最小步数的问题,从一个开始,其中链的每个后续成员等于同一链的两个先前成员的总和。

这是数论中的一个经典问题,在优化指数,密码学中的计算以及分析某些算法的复杂性方面都有应用。

理论部分

添加剂фепочка长度 它是一个序列 ,如 . 每个元素是前两个术语的总和,不一定可区分。

[布劳尔之链](https://en.wikipedia.org/wiki/Addition_chain#Brauer_chain "wp:加法链")用于 是一个加成链,其中 . 每个元素都使用前一个元素作为求和。

在这个例子中,我们对最小长度的链感兴趣。 .

任务

为所有人 输出以下内容:

  • ,

-Brower长度链的数量 .

功能 trypermutation

功能 trypermutation 递归地构建此类总和的所有可能序列,试图以最少的步骤数实现目标。 这是通过经历所有可能的组合(排列)来完成的。

主要部分

检查序列当前状态的功能 — checksequence

In [ ]:
"""
检查递归完成的条件或继续递归。

pos--当前步数(递归深度),
seq--当前价值链,
n--目标值,
minlen是允许的最大深度(到目前为止找到的最小长度)。

返回一个元组:
(minimal_length_found, number_of_ways_with_that_length)
"""
function checksequence(pos, seq, n, minlen)
    # 如果我们已经超过了已知的最小值,我们不应该进一步检查。
    pos > minlen || seq[1] > n ? (minlen, 0) :

    # 如果第一个值大于N,则链是不好的。
    seq[1] == n ? (pos, 1) : # 我们已经达到了目标! 我们返回步数和一个找到的链。

    # 如果你还没有达到最大值,但你可以继续迭代。:
    pos < minlen ? trypermutation(0, pos, seq, n, minlen) : (minlen, 0) # 否则,他们还是走了过来
end
Out[0]:
checksequence

尝试所有有效排列的递归函数 — trypermutation

In [ ]:
"""
trypermutation(i, pos, seq, n, minlen) 

i是最后一个元素的索引,可以是求和,
pos--当前链中有多少项(链长),
seq--数字本身的字符串,
n是目标(期望)数,
minlen是当前最佳发现的链长。

返回一对(best_line,获取此长度的方式数)。
"""
function trypermutation(i, pos, seq, n, minlen)
    if i > pos
        return minlen, 0 # 我们没有发现任何新的东西,所以我们只是退回最低限度。
    end
    
    new_seq = deepcopy(seq) # 创建链的副本
    pushfirst!(new_seq, seq[1] + seq[i+1]) # 在开头添加一个新数字(左侧):a[j]=a[1]+a[i+1]

    res1 = checksequence(pos + 1, new_seq, n, minlen) # 我们进一步检查收到的链

    res2 = trypermutation(i + 1, pos, seq, n, res1[1]) # 让我们尝试另一种选择i->i+1

    # 选择最佳结果:
    if res2[1] < res1[1]
        return res2
    elseif res2[1] == res1[1]
        return res2[1], res1[2] + res2[2] # 如果相等,我们将路径数相加。
    else
        error("具有大i的结果小于具有较小i的结果–逻辑上是错误的!")
    end
end
Out[0]:
trypermutation

主程序:输出一组数字的结果

一组测试数字:对于它们中的每一个,将找到添加剂链的最小长度。

In [ ]:
for num in [7, 14, 21, 29, 32, 42, 64, 47, 79, 191, 382, 379]
    (minlen, nchains) = trypermutation(0, 0, [1], num, 12) # 起始链为[1];允许的最大长度为12
    println("N = ", num)
    println("最小链长:L(n)= ", minlen)
    println("这个长度的链的数量(Brower的数量): ", nchains)
end
N = 7
Минимальная длина цепочек: L(n) = 4
Количество цепочек такой длины (число Брауэра): 5
N = 14
Минимальная длина цепочек: L(n) = 5
Количество цепочек такой длины (число Брауэра): 14
N = 21
Минимальная длина цепочек: L(n) = 6
Количество цепочек такой длины (число Брауэра): 26
N = 29
Минимальная длина цепочек: L(n) = 7
Количество цепочек такой длины (число Брауэра): 114
N = 32
Минимальная длина цепочек: L(n) = 5
Количество цепочек такой длины (число Брауэра): 1
N = 42
Минимальная длина цепочек: L(n) = 7
Количество цепочек такой длины (число Брауэра): 78
N = 64
Минимальная длина цепочек: L(n) = 6
Количество цепочек такой длины (число Брауэра): 1
N = 47
Минимальная длина цепочек: L(n) = 8
Количество цепочек такой длины (число Брауэра): 183
N = 79
Минимальная длина цепочек: L(n) = 9
Количество цепочек такой длины (число Брауэра): 492
N = 191
Минимальная длина цепочек: L(n) = 11
Количество цепочек такой длины (число Брауэра): 7172
N = 382
Минимальная длина цепочек: L(n) = 11
Количество цепочек такой длины (число Брауэра): 4
N = 379
Минимальная длина цепочек: L(n) = 12
Количество цепочек такой длины (число Брауэра): 6583

主循环是如何工作的?

对于列表中的每个数字,执行以下操作:

  1. 开始递归迭代。 trypermutation,从起始链开始 [1].
  2. 递归通过添加一个新项作为任何两个现有项的总和来生成所有可能的序列。
  3. 功能 checksequence 跟踪期望值的实现(== n),如果新链比当前链短,则进行修复。
  4. 在迭代结束时,每个输入输出两个数字:
    • L(n) -添加剂链的最小长度;
      -最小Brower链的数量(具有不同的添加顺序,但长度相同)。

结论

我们已经回顾了在Julia环境中使用递归的全迭代方法构建最小加性链的算法的实现。 对于一组数字,找到相应链的最小长度,并计算此类链(所谓的Brower链)的数量。 这种技术例如对于用于快速指数化和分析密码系统中操作的复杂性的高效算法是有用的。

该示例是使用[罗塞塔代码]的材料开发的(https://rosettacode.org/wiki/Addition_chains