科拉茨猜想,统计最终变成1所运算的次数,以及数列是否有重复

82 篇文章 3 订阅

 

科拉茨猜想(Collatz Conjecture)3N+1 问题

任取一个正整数,如果这个数是偶数,则除以二。如果是奇数,乘以3再加1。重复上述步骤,最后起始数都会变成1时停止。这就是著名的科拉茨猜想。

这可能不是世界上最有趣的游戏,但请你多玩一会儿。我向你保证,这将是很有趣。

例如,如果我们从7开始,我们会得到下面的数列(从现在开始,我们称它为科拉茨序列)。

7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1.如果我们从19开始,我们得到:

19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1.请注意,在某一时刻,我们在上述两个序列中都得到了数字22,因此它们的“尾巴”是一样的。

问题是:我们总是在1处结束吗?

信不信由你,上述问题是一个深奥的谜题。尽管很多非常聪明的数学家做出了巨大的努力,但这个问题仍然没有得到解决。

这个问题被称为 "科拉茨猜想"。

解决方案

那么,解是什么样子的呢?我们需要证明两件事。首先,我们需要证明所有数列都是有界的。换句话说,不存在无限的科拉茨数列。我所说的无限是指序列中的数字集是无限大的。第二,我们需要证明不可能出现循环。也就是说,在科拉茨数列中,我们永远不会遇到一个数字两次。如果我们从1开始,那么4,2,1的序列就会无限期地重复。

当然,还有另一种解决办法。这个猜想可能是错的,数学家试图验证它,取的起始值约为2^68。1958年,波利亚猜想(Pòlya conjecture)被一个大约1.845×10^361的反例所推翻,这比2^68这数字大得多。

实际上,这里还可能发生另一件事。数学家们往往不大谈论这个问题,因为这是很悲伤的想法。科拉茨猜想在我们的公理系统中可能是无法解决的,也就是说,无论我们如何努力,我们都无法破解它。

我们并不是证明科拉茨猜想,只是测试下 递归 和循环的算法用时,以及产生的数列队列。

新建控制台应用程序CollatzConjectureDemo,测试科拉茨猜想运算次数以及产生的数列是否存在重复元素。

测试程序如下:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CollatzConjectureDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            //科拉茨猜想: 任取一个正整数,如果这个数是偶数,则除以2。如果是奇数,乘以3再加1。重复上述步骤,最后起始数都会变成1。
            Console.SetWindowSize(120, 50);
            Task taskRecursion = Task.Run(() => { AlgorithmTimespan(CalculateCollatzConjectureUseRecursive, nameof(CalculateCollatzConjectureUseRecursive)); });
            Task taskIterator = Task.Run(() => { AlgorithmTimespan(CalculateCollatzConjecture, nameof(CalculateCollatzConjecture)); });
            Task.WaitAll(taskIterator, taskRecursion);
            Console.ReadLine();
        }

        /// <summary>
        /// 算法用时
        /// </summary>
        /// <param name="CalculateMethod">计算方法</param>
        /// <param name="methodName"></param>
        static void AlgorithmTimespan(Func<int, List<int>> CalculateMethod, string methodName)
        {
            Stopwatch stopwatch = Stopwatch.StartNew();
            for (int number = 100; number < 120; number++)
            {
                List<int> list = CalculateMethod(number);
                Console.WriteLine($"【{methodName.PadRight(38)}】数字【{number}】,是否存在重复:{list.ExistDuplicate()},轮回个数:【{list.Count}】【{string.Join(",", list)}】");
            }
            Console.WriteLine($"【{methodName.PadRight(38)}】,对【20】个数字进行科拉茨猜想运算,用时【{stopwatch.Elapsed.TotalMilliseconds}】ms");
        }

        /// <summary>
        /// 【循环方法】返回科拉茨猜想依次变成1的数列顺序
        /// </summary>
        /// <param name="startingNumber"></param>
        /// <returns></returns>
        static List<int> CalculateCollatzConjecture(int startingNumber)
        {
            List<int> list = new List<int>();
            while (startingNumber > 1)
            {
                if ((startingNumber & 1) == 0)
                {
                    //如果是偶数,就除以2
                    startingNumber = startingNumber / 2;
                }
                else
                {
                    //如果是奇数,乘以3再加1,运算后,又变成偶数了
                    startingNumber = startingNumber * 3 + 1;
                }
                list.Add(startingNumber);
            }
            return list;
        }

        /// <summary>
        /// 【递归方法】返回科拉茨猜想依次变成1的数列顺序
        /// </summary>
        /// <param name="startingNumber"></param>
        /// <returns></returns>
        static List<int> CalculateCollatzConjectureUseRecursive(int startingNumber)
        {
            List<int> list = new List<int>();
            CalculateCollatzConjectureRecursive(startingNumber, ref list);
            return list;
        }

        /// <summary>
        /// 【递归方法】返回科拉茨猜想依次变成1的数列顺序
        /// </summary>
        /// <param name="startingNumber"></param>
        /// <param name="list"></param>
        static void CalculateCollatzConjectureRecursive(int startingNumber, ref List<int> list)
        {
            if (startingNumber > 1)
            {
                if ((startingNumber & 1) == 0)
                {
                    //如果是偶数,就除以2
                    list.Add(startingNumber / 2);
                    CalculateCollatzConjectureRecursive(startingNumber / 2, ref list);
                }
                else
                {
                    //如果是奇数,乘以3再加1,运算后,又变成偶数了
                    list.Add(startingNumber * 3 + 1);
                    CalculateCollatzConjectureRecursive(startingNumber * 3 + 1, ref list);
                }
            }
        }
    }

    /// <summary>
    /// 判断集中中是否存在重复的元素
    /// </summary>
    public static class DuplicateUtil
    {
        /// <summary>
        /// 扩展方法:判断集合中是否存在重复的元素
        /// 扩展方法:方法所在的类(类名可以是任意的)一定是静态的,参数指代某种类型的扩展方法,类型前面加this关键字,比如Method(this T)代表类型T的扩展方法Method。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <returns></returns>
        public static bool ExistDuplicate<T>(this IEnumerable<T> list)
        {
            HashSet<T> hashset = new HashSet<T>();
            return list.Any(e => !hashset.Add(e));
        }

        /// <summary>
        /// 判断是否有重复的元素,并 返回第一个重复的元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="t"></param>
        /// <returns></returns>
        public static bool ExistDuplicate<T>(IEnumerable<T> list, out T t)
        {
            t = default(T);
            if (list == null)
            {
                return false;
            }
            HashSet<T> hashset = new HashSet<T>();
            foreach (T item in list)
            {
                //如果添加数据失败,说明有重复的元素
                if (!hashset.Add(item))
                {
                    t = item;
                    return true;
                }
            }
            return false;
        }
    }
}

运行结果

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

斯内科

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值