Collat​​z序列 - 减少错误

时间:2016-07-29 09:15:01

标签: c#

为正整数集定义了以下迭代序列:

n→n / 2(n是偶数)

n→3n + 1(n为奇数)

使用上面的规则并从13开始,我们生成以下序列:

13→40→20→10→5→16→8→4→2→1

可以看出,该序列(从13开始,在1结束)包含 10个学期。虽然尚未证实(Collat​​z问题),但据认为所有起始数字都以1结束。

哪个起始编号低于一百万,产生最长的链?

这是我对手头问题的解决方案。

static void Main(string[] args)
{
    int possCounter = 0;
    int largestChain = 0;
    int largestChainNum = 0;
    int chainNum = 0;
    for (int i = 2; i <= 999999; i++)
    {
        chainNum = i;
        possCounter = 1;
        while (chainNum != 1)
        {
            if (chainNum % 2 == 0)
            {
                chainNum = chainNum / 2;
            }
            else
            {
                chainNum = (3 * chainNum) + 1;
            }
            possCounter++;
            Console.WriteLine(chainNum);
        }
        if (possCounter > largestChain)
        {
            largestChainNum = i;
            largestChain = possCounter;
        }
    }
    Console.WriteLine(largestChainNum);
    Console.ReadLine();
}

我在Console.WriteLine(chainNum)之后放置possCounter++只是为了检查我的代码是否正常运行。它会正常运行,然而,在某一点它开始运行负数。我不知道我的代码出了什么问题。

2 个答案:

答案 0 :(得分:1)

这是一个整数溢出。如果你使用更大的类型(如Long),它应该可以正常工作。

答案 1 :(得分:1)

解决问题(跟踪序列)时,您将遇到数字

56991483520

大于int.MaxValue,因此你会有溢出;我建议将long用于序列成员。一个优化提示更多是通过序列项的系列更新:已跟踪

13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1

您知道402016的长度,并且无需再次计算这些数字

private static Dictionary<long, int> s_Counts = new Dictionary<long, int>() {
  {1, 1},
};

private static void AppendCounts(long n) {
  List<long> list = new List<long>();

  for (; !s_Counts.ContainsKey(n); n = n % 2 == 0 ? n / 2 : 3 * n + 1) 
    list.Add(n);

  int count = s_Counts[n];

  for (int i = list.Count - 1; i >= 0; --i)
    s_Counts.Add(list[i], count + list.Count - i);
}

...

for (int i = 1; i < 1000000; ++i)
  AppendCounts(i);

KeyValuePair<long, int> max = new KeyValuePair<long, int>(0, 0);

foreach (var pair in s_Counts)
  if (pair.Value > max.Value)
    max = pair;

Console("{0} generates {1} values", max.Key, max.Value); 

结果是

837799 generates 525 values