陷入无限循环?(也许) 我试图用C++完成Euler项目,我真的被卡住了。现在,当我运行这个问题时,它到目前为止一直停留在:计数最高的数字:113370,计数155 到目前为止:计数最高的数字,但当我尝试将I值更改为113371以上时,它会起作用。发生了什么事

陷入无限循环?(也许) 我试图用C++完成Euler项目,我真的被卡住了。现在,当我运行这个问题时,它到目前为止一直停留在:计数最高的数字:113370,计数155 到目前为止:计数最高的数字,但当我尝试将I值更改为113371以上时,它会起作用。发生了什么事,c++,collatz,C++,Collatz,问题是: 下面的迭代序列是为一组正函数定义的 整数:n→ n/2(n为偶数)n→ 3n+1(n为奇数) 使用上面的规则,从13开始,我们生成以下内容 顺序: 十三,→ 40→ 20→ 10→ 5.→ 16→ 8.→ 4.→ 2.→ 1可以看出 序列(从13开始到1结束)包含10个术语。 虽然它还没有被证明(Collatz问题),但它确实存在 我想所有的起始数字都是1。哪个起始号码, 在一百万以下,生产最长的链条 #包括 int main(){ 整数限制=1000000; int highNum,

问题是:

下面的迭代序列是为一组正函数定义的 整数:n→ n/2(n为偶数)n→ 3n+1(n为奇数)

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

十三,→ 40→ 20→ 10→ 5.→ 16→ 8.→ 4.→ 2.→ 1可以看出 序列(从13开始到1结束)包含10个术语。 虽然它还没有被证明(Collatz问题),但它确实存在 我想所有的起始数字都是1。哪个起始号码, 在一百万以下,生产最长的链条

#包括
int main(){
整数限制=1000000;
int highNum,number,i;
int高计数=0;
整数计数=0;

对于(number=13;number,使用您的算法计算几个时间相同的序列。 您可以缓存以前的数字的结果并重用它们

比如:

void compute(std::map<std::uint64_t, int>& counts, std::uint64_t i)
{
    std::vector<std::uint64_t> series;
    while (counts[i] == 0) {
        series.push_back(i);
        if ((i % 2) != 0) {
            i = (i * 3) + 1;
        } else {
            i /= 2;
        }
    }
    int count = counts[i];
    for (auto it = series.rbegin(); it != series.rend(); ++it)
    {
        counts[*it] = ++count;
    }
}

int main()
{
    const std::uint64_t limit = 1000000;

    std::map<std::uint64_t, int> counts;
    counts[1] = 1;
    for (std::size_t i = 2; i != limit; ++i) {
        compute(counts, i);
    }
    auto it = std::max_element(counts.begin(), counts.end(),
        [](const std::pair<std::uint64_t, int>& lhs, const std::pair<std::uint64_t, int>& rhs)
        {
            return lhs.second < rhs.second;
        });
    std::cout << it->first << ":" << it->second << std::endl;
    std::cout << limit-1 << ":" << counts[limit-1] << std::endl;
}
void计算(标准::映射和计数,标准::uint64\u t i)
{
std::向量系列;
while(计数[i]==0){
系列。推回(i);
如果((i%2)!=0){
i=(i*3)+1;
}否则{
i/=2;
}
}
int count=计数[i];
用于(自动it=series.rbegin();it!=series.rend();++it)
{
计数[*it]=++计数;
}
}
int main()
{
常数标准::uint64\u t限制=1000000;
地图计数;
计数[1]=1;
对于(标准::尺寸\u t i=2;i!=limit;++i){
计算(计数,i);
}
auto it=std::max_元素(counts.begin(),counts.end(),
[](常数std::pair&lhs,常数std::pair&rhs)
{
返回左秒<右秒;
});

std::cout first不要一遍又一遍地重新计算相同的中间结果

给定

然后,
collatz(x)
的值只取决于
x
,而不取决于调用它的时间。(换句话说,
collatz
是a。)因此,您可以选择
collatz(x)的值
用于
x
的不同值。为此,可以使用
std::map
std::unordered_map

供参考,是完整的解决方案


现在开始计时(2.6秒)。

您将获得整数溢出。请像这样更新代码并亲自查看:

if (( i % 2 ) != 0 ) {
    int prevI = i;
    i = ( i * 3 ) + 1;
    if (i < prevI) {
        printf("oops, i < prevI: %d\n", i);
        return 0;
    }
    count++;
}
如果((i%2)!=0){
int-prevI=i;
i=(i*3)+1;
if(i
您应该将
i
的类型更改为
long
unsigned long
以防止溢出


(是的,缓存中间结果)

记住所有中间结果(最多一个适当高的数字)。
此外,请使用足够大的类型:

#include <stdio.h>

static int collatz[4000000];
unsigned long long collatzmax;

int comp(unsigned long long i) {
  if(i>=sizeof collatz/sizeof*collatz) {
      if(i>collatzmax)
        collatzmax = i;
      return 1 + comp(i&1 ? 3*i+1 : i/2);
  }
  if(!collatz[i])
      collatz[i] = 1 + comp(i&1 ? 3*i+1 : i/2);
  return collatz[i];
}

int main() {
  collatz[1] = 1;
  int highNumber= 1, highCount = 1, c;
  for(int i = 2; i < 1000000; i++)
    if((c = comp(i)) > highCount) {
      highCount = c;
      highNumber = i;
    }
  printf( "The number with the highest count: %d with the count of %d\n",
        highNumber, highCount );
  printf( "Highest intermediary number: %llu\n", collatzmax);
}


顺便说一句:遇到的最高中间值需要36位来表示为无符号数。

如果程序对相对较小的数字正确工作,但“陷入无限循环”对于大数,它可能不是一个无限循环,您的算法很慢。您的问题是您正在反复重新计算相同的部分结果。请检查您使用的数据类型的限制,使用无符号长循环int@PictureMeAndYou:您的限制是1000000,但当您计算每个序列的长度时,一些中间值将被忽略需要32位
int
的范围。实际上,按照同样的思路,在显而易见的策略中,您可以立即丢弃1-500000之间的每个数字作为最长的链,因为值加倍总是会使链长一个。您还可以丢弃
(N-1)中的所有数字%3==0
。这就减少了66%的可能性。奇怪的是,它却在完全相同的位置停止spot@PictureMeAndYou:使用提供的代码,我可以在10秒钟内得到一个结果。@Jarod42:可以。@blastfurny:为什么是
std::unique\u ptr
而不是
std::vector
?@MooingDuck:回想起来,我想我想要避免初始化容器的值,它的输入量比
reserve/push_back
要少。是的,我知道有更快的方法可以做到这一点,但我想试试我的方法,因为它对我来说是原创的,并且理解为什么它不起作用。@PictureMeAndYou:你的方法不起作用,因为你的算法太慢了。好吧,我想I don’编译和运行需要一段时间,我从来不知道它会完全停止?@PictureMeAndYou:如果你编写的程序需要一千年才能完成运行,无论出于何种实际目的,你的程序都不会停止。@EduardoLeón:一旦我将所有内容更改为
long long,他的代码在我的机器上只需要大约3.7秒
@Jarod42:正确的幻数有点太高了。添加了计算它的代码。+1我认为,您只需要迭代奇数。@PetrBudnik:我不相信这是一个有效的优化(尽管我根据类似的推理确定了几个有效的优化)@PetrBudnik:你只需要迭代三个数字中的两个500000-1000000:where
N%3==1
为假。最后我打赌这是一样的,因为剩下的大部分都会被记住。
if (( i % 2 ) != 0 ) {
    int prevI = i;
    i = ( i * 3 ) + 1;
    if (i < prevI) {
        printf("oops, i < prevI: %d\n", i);
        return 0;
    }
    count++;
}
#include <stdio.h>

static int collatz[4000000];
unsigned long long collatzmax;

int comp(unsigned long long i) {
  if(i>=sizeof collatz/sizeof*collatz) {
      if(i>collatzmax)
        collatzmax = i;
      return 1 + comp(i&1 ? 3*i+1 : i/2);
  }
  if(!collatz[i])
      collatz[i] = 1 + comp(i&1 ? 3*i+1 : i/2);
  return collatz[i];
}

int main() {
  collatz[1] = 1;
  int highNumber= 1, highCount = 1, c;
  for(int i = 2; i < 1000000; i++)
    if((c = comp(i)) > highCount) {
      highCount = c;
      highNumber = i;
    }
  printf( "The number with the highest count: %d with the count of %d\n",
        highNumber, highCount );
  printf( "Highest intermediary number: %llu\n", collatzmax);
}