我一直在尝试解决这个问题:
为正数的集合定义了以下迭代序列 整数:
n→n / 2(n为偶数)
n→3n + 1(n为奇数)使用上面的规则并从13开始,我们生成以下内容 顺序:
13→40→20→10→5→16→8→4→2→1可以看到,这个顺序(从13开始到1结束) 包含10个字词。尽管尚未得到证实(Collatz 问题),可以认为所有起始数字都以1结尾。
哪个起始编号小于一百万,会产生最长的链条?
注意:链条一旦开始,条款就可以超过一个 百万。
并且我实现了以下代码,但这似乎并没有给我正确的答案。它计算910107作为给出最长链的起始数字,但是答案应该是837799。这有什么问题?
#include<stdio.h>
int main(void)
{
int count=1;
int last_count =0;
int num=13;
int temp;
int Largest_Num=0;
for(int i=num;i<1000000;i++)
{
temp = i;
while(temp>1)
{
if(temp % 2 == 0)
{
temp/=2;
}
else
{
temp =(3*temp)+1;
}
count++;
}
if(last_count < count)
{
last_count = count;
Largest_Num = i;
}
count =1;
}
printf("%d\n",last_count);
printf("%d",Largest_Num);
return 0;
}
答案 0 :(得分:1)
我得到910107作为给出最长链的起始号码,但答案应该是837799
int 太短,无法管理 temp 所需的大量数字,但您溢出了
这意味着您的 int 使用32位,在这种情况下 int 仅使用31位作为正数,而您需要32
您可以将 temp 声明为 unsigned int (比起 int 多1位,因为您只需要正数),或使用 long (如果您使用的是64位),或者 long long 以确保至少有64位
答案 1 :(得分:0)
正如@bruno在他的回答中观察到的那样,您超出了系统的int
数据类型的容量。问题甚至暗示这是您可能会遇到的问题,当它说:
注意:链条启动后,允许的条款就可以超过一百万。
以上多少?从问题上还不清楚,所以“如何确定哪种数据类型足够?”这个问题应该立即浮现在脑海。当然,前面的问题“我应该选择哪种数据类型?”是至少应该一直得到真正关注的时刻。
假设您对要计算的序列没有先验知识,并且在一般情况下没有明确的方法确定其元素的可靠上限,确定哪种数据类型将需要实际执行(尝试)计算并观察溢出。或者,您可以选择一个您认为足够的数据类型,然后进行验证以证明它实际上是足够的。如果不是,那么请使用其他数据类型再试一次。
在这种情况下,防止溢出很容易。唯一需要监视的变量是temp
,仅当您计算temp =(3*temp)+1
时,其值才会增加。您知道类型int
的最大值是(INT_MAX
),并且很容易用代数方法确定计算不超过temp
的{{1}}的最大值:它是INT_MAX
。因此,您可以执行以下操作:
(INT_MAX - 1) / 3
如果最终导致断言失败(使用类型#include <assert.h>
#define TEMP_BOUND ((INT_MAX - 1) / 3)
// ...
if(temp % 2 == 0) {
temp /= 2;
} else {
assert(temp <= TEMP_BOUND);
temp = (3 * temp) + 1;
}
时将失败),则可以使用支持更大最大值的数据类型重试;否则,请重新启动。只需确保随后针对新数据类型适当地更新int
宏即可。
我还应该观察到,还有一种选择可以使用任意精度的数据类型执行计算,例如可以从各种第三方库(例如GMP)中获得。但是,这将慢得多,并且代码也将更加复杂,因此,对于这种情况,我建议使用上面概述的反复试验方法,至少要达到您确定没有内置数据类型足以解决问题。