考拉兹猜想(改版)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/TuringGo/article/details/82995828

考拉兹猜想

考拉兹猜想是一个数学上的未解之谜,至今仍未解决,考拉兹猜想的内容如下:

  • 对于自然数 n 循环执行如下操作
  • n n 是偶数,用 n n 除以 2 2
  • n n 是奇数,用 n n 乘以 3 3 后加 1 1
  • 如此循环操作,无论初始值是什么数字,最终都会得到 1 1 。2009年验证到了数字 5 , 764 , 607 , 523 , 034 , 234 , 880 5,764,607,523,034,234,880 仍然满足这一猜想,但没有得到数学上的证明,就无法断言对于任何一个自然数都满足该猜想。

问题

这里我们的考拉兹猜想的改版为:若初始值 n n 是一个偶数,也对 n n 进行 n n 乘以 3 3 1 1 的操作;后面数字的计算,按照考拉兹猜想来,考虑这样最后能够回到初始值的数字。

例如: 4 13 40 20 10 5 16 8 4 4 \to 13 \to 40 \to 20 \to 10 \to 5 \to 16 \to 8 \to 4 ,但初始值为 6 ,最终就不会是 1 。

求小于 10000 10000 的偶数中,像上述的 2 2 或者 4 4 这样“能回到初始值的数”有多少个?

分析

  • 虽然本题在初始值时,改变了考拉兹猜想的规则,但只要继续计算下去,其最终的数字还是会像考拉兹猜想一样,最终值归为数字 1 1 。这是因为,在对某一个数字进行一系列的计算时,我们将第一步分离出去,那么剩下的 n 1 n-1 步骤就全都满足考拉兹猜想,因此我们可以将第一步计算的结果作为一个考拉兹猜想计算的输入值,那么接下来的计算就是纯粹的考拉兹猜想计算了,所以最终数字还是 1 1
  • 对于任何一个数字的考拉兹猜想计算而言,最终都会归于这样一个数字链: . . . 4 2 1 ...4 \to 2 \to 1 ,若继续计算下去,就会有循环数字链: . . . 4 2 1 4 2 1 4 2 1 . . . ... 4 \to 2 \to 1 \to 4 \to 2 \to 1 \to 4 \to 2 \to 1 \to ... ,若计算的数字是大于 4 4 的,则一旦结果达到 1 1 ,就不会再出现该数字了
  • 因此,对于本题而言,若某个数字能回到初始值,那么就意味着该数字一定出现在数字 1 1 之前;否则,该数字就无法再计算链中回到初始值。

算法

  • 对每一个数字进行 n u m 3 + 1 num * 3 + 1 的计算
  • 当结果不是 1 1 的时候,就进行考拉兹猜想的计算;其中考拉兹猜想计算中,先判断是否是偶数,然后再进行不同的计算,这里用三运算符实现更简洁
  • 每个数字最终都会达到 1 1 ,在每个数字到达 1 1 之前,若出现与原来的初始输入的参数相等,则说明该数字计算链中出现了返回初始值的情况,此时跳出循环返回 T r u e True

Python代码实现

def is_loop(num):
    n = num * 3 + 1
    while n != 1:
        n =  n * 3 + 1 if n % 2 else n // 2
        if n == num:
            return True

count = 0
for num in range(2, 10000, 2):
    count += 1 if is_loop(num) else 0
print(count)

# 34

递归算法

分析

  • 基于我们上述分析可知,只需要将改版过后的考拉兹猜想计算的第一步的计算结果,视为一个输入,则接下来的计算就是考拉兹猜想的计算了。
  • 考拉兹猜想的计算,本质上就是一个递归的过程。其递归部分是:若 n n 是偶数,则用 n n 除以 2 2 ;若 n n 是奇数,则用 n n 乘以 3 3 后加 1 1 。结合本题的特点,这个递归的终止条件是:若计算结果为 1 1 ,则表示没有回到数字的初始值;若计算结果为初始值,则表示该数字存在回到初始值的情况

算法

  • 因为是递归函数,所以参数n会不断变化,需要声明一个global全局变量用于保存当前传入的数字。
  • 递归函数只计算 n 1 n-1 步骤的考拉兹猜想部分,第一步的计算结果由函数的参数直接传入。
  • 若函数计算结果出现了 1 1 ,则表示该数字不存在回到初始值特性,返回 F a l s e False ;若函数计算结果出现了全局变量初始值,则返回 T r u e True ;若两者都不是,则继续递归下去。

Python代码实现

def is_loop(n):
    global num
    if n == 1:
        return False
    elif n == num:
        return True
    else:
        return is_loop(n=n*3+1 if n%2 else n//2)

num = None
count = 0
for n in range(2, 10000, 2):
    num = n
    if is_loop(n*3+1):      #将第一步的结果作为输入
        print(n, end=' ')   #打印符合要求的数字
        count += 1
print('\n', count)

# 2 4 8 10 14 16 20 22 26 40 44 52 106 184 206 244 274 322 526 650 668 790 866 976 1154 1300 1438 1732 1780 1822 2308 2734 3238 7288 
# 34

猜你喜欢

转载自blog.csdn.net/TuringGo/article/details/82995828