3n + 1猜想的算法指导

时间:2012-09-10 23:04:03

标签: c# algorithm math collatz

好的,我知道这听起来像是家庭作业;但这有任何办法。我正在尝试使用C#解决此问题problem。问题描述的摘录如下所示:

  

给定输入n,可以确定数字的数量   印刷(包括1)。对于给定的n,这被称为   循环长度n。在上面的例子中,循环长度22是16。   对于任何两个数字i和j,您将确定i和j之间所有数字的最大循环长度。

问题

除了一件事,我知道一切,周期长度。我完全不明白。我发现文本的定义含糊不清。我假设,循环长度是序列中的数字,所以假设输入为10,循环长度为8.但我只是不确定。您不需要代码,但我只能提供指导。

此外,我已经知道如何从标准输入和输出中读取。由于问题在于编程竞争格式。

我实现显示n作为输入的数字序列

static void collatz(ref int n)
{    
     if (n % 2 == 0)
     {
          n /= 2;
     }
     else
     {
          n = (3 * n) + 1;
     }
     Console.WriteLine(n);
}

static int GetCycleLength(int n)
{
     if (n > 0)
     {
          int count = 1;
          while (n != 1)
          {
               collatz(ref n);
               count++;
          }
          return count;
     }
     else
     {
          return -1;
     }
}

注释

虽然不是作业,但我想把它作为家庭作业,所以我把它作为标签之一。

4 个答案:

答案 0 :(得分:3)

您应该使用动态编程。也就是说,如果你为数字j工作并且在为j工作时遇到k。那么你不应该再次重复k的整个工作。

从j开始,然后去找我。假设您正在查找数字n的循环长度。在找到n的循环长度时,假设您遇到数字:n,n8,n7,n6,...,n1。然后循环长度为n为9,对于n8为8,对于n7为7.存储数组或映射中所有此类数字的循环长度。当您遇到相同的数字以查找任何不同数字的周期长度时,可以随处重用它们。这将为您提供解决此问题的最佳解决方案。

请参阅http://en.wikipedia.org/wiki/Dynamic_programming#Fibonacci_sequence

的动态编程示例

答案 1 :(得分:2)

循环长度是算法必须应用于原始自然数/整数以便最终达到1的次数。

示例,如果您从7开始:

  1. 7是奇数,所以我们使用算法3(7)+ 1 = 22
  2. 22甚至是我们使用22/2 = 11
  3. 11是奇数,所以我们使用算法3(11)+ 1 = 34
  4. 34甚至是我们使用算法34/2 = 17
  5. 17是奇数,所以我们使用算法3(17)+ 1 = 52
  6. 52甚至是我们使用算法52/2 = 26
  7. 26甚至是我们使用算法26/2 = 13
  8. 13是奇数,因此我们使用算法13(3)+ 1 = 40
  9. 40甚至是我们使用算法40/2 = 20
  10. 20甚至是我们使用算法20/2 = 10
  11. 10甚至是我们使用算法10/2 = 5
  12. 5是奇数,因此我们使用算法5(3)+ 1 = 16
  13. 16甚至是我们使用算法16/2 = 8
  14. 8甚至是我们使用算法8/2 = 4
  15. 4甚至是我们使用算法4/2 = 2
  16. 2甚至是我们使用算法2/2 = 1
  17. 我们已将算法 16 应用于数字7,我们得到1.因此,16是周期长度。

    代码效果提示 - 您可以使用按位运算,而不是在collatz(ref int n)中进行乘法和除法。这将使性能得到显着提升。

答案 2 :(得分:1)

对于特定的起始值(n),循环长度只是达到1所需的数量(包括最后的1)。对于10

  

10 5 16 8 4 2 1

因此周期长度为7。

因此,对于此问题,您必须从i循环到j,确定迭代的每个整数的循环长度,并返回遇到的最大循环长度。您可能希望查看另一个答案所提到的dynamic programming(即存储先前计算的周期长度,然后在将来的计算中使用这些存储的值)。

答案 3 :(得分:0)

所提到的案文对周期长度的定义并不含糊不清;它说:“给定输入n,可以确定打印的数字...对于给定的n,这称为循环长度n”。例如,给定输入20,参考过程打印出20 10 5 16 8 4 2 1,因此“周期长度为20”为8.在某种意义上,您的程序模拟 n ,查找并打印遇到的最大周期长度。

注意,使用动态编程的建议可能会有些误导。您实际可以使用的是 memoization ,即记录以前处理过的输入的全部或部分结果。记录结果很麻烦,所以如果你的程序足够快而没有记忆,那么就不要费心了。问题是假设“没有操作溢出32位整数”。如果您不做进一步的假设并记录所有中间结果,则需要一个能够处理数十亿个不同值的字典数据结构。如果您对最大循环长度做出假设,则程序可能会失败。无论如何,一种方法是选择一些大数K并分配一个整数数组M;将数组初始化为全零,M[1] = 1除外。在Collat​​z例程中,每次执行步骤4( n←3n + 1)时,将1推入一堆位。 (堆栈中的位数应不小于最大循环长度。)每次执行步骤5( n←n / 2)时,将0推入堆栈。

如果您在任何步骤中找到M[n] > 0,那么您知道您已经将n的周期长度计算为c = L = M[n]。此时,您可以展开位堆栈并返回L.在展开后,在每次弹出后,如果您弹出0,则计算n(如n = 2*n;如果您弹出0,则计算n = (n-1)/3弹出1),执行++c,如果n<K设置M[n] = c