陷入无限循环?(也许)

Stuck in an infinite loop? (Maybe)

本文关键字:也许 无限循环      更新时间:2023-10-16

我正试图用c++完成Project Euler Problem 14,但我确实被卡住了。现在,当我运行这个问题时,它被困在"迄今为止":计数最高的数字:113370,计数为155到目前为止:计数最高的数字,但当我尝试将I值更改为113371以上时,它会起作用。发生了什么事??

问题是:

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

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

13→40→20→10→5.→16→8.→4.→2.→1可以看出序列(从13开始,到1结束)包含10个项。虽然它还没有被证明(Collatz问题),但它是以为所有的起始数字都以1结束。哪个起始号码,低于一百万,生产最长的链条?

#include<stdio.h>
int main() {
    int limit = 1000000;
    int highNum, number, i;
    int highCount = 0;
    int count = 0;
    for( number = 13; number <= 1000000; number++ )
    {
        i = number;
        while( i != 1 ) {
            if (( i % 2 ) != 0 ) {
                i = ( i * 3 ) + 1;
                count++;
            }
            else {
                count++;
                i /= 2;
            }
        }
        count++;
        printf( "So Far: the number with the highest count: %d with the count of %dn",
                     number, count );
        if( highCount < count ) {
            highCount = count;
            highNum = number;
        }
        count = 0;
        //break;
    }
    printf( "The number with the highest count: %d with the count of %dn",
            highNum, highCount );
}

您得到的是整数溢出。像这样更新你的代码并亲自查看:

if (( i % 2 ) != 0 ) {
    int prevI = i;
    i = ( i * 3 ) + 1;
    if (i < prevI) {
        printf("oops, i < prevI: %dn", i);
        return 0;
    }
    count++;
}

您应该将i的类型更改为long longunsigned long 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 %dn",
        highNumber, highCount );
  printf( "Highest intermediary number: %llun", collatzmax);
}

关于coliru:http://coliru.stacked-crooked.com/a/773bd8c5f4e7d5a9

运行时间较小的变体:http://coliru.stacked-crooked.com/a/2132cb74e4605d5f

The number with the highest count: 837799 with the count of 525
Highest intermediary number: 56991483520

BTW:遇到的最高中介需要36位来表示为无符号数字。

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

类似于:

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;
}

演示(10秒)

不要一次又一次地重新计算相同的中间结果!

给定

typedef std::uint64_t num;  // largest reliable built-in unsigned integer type
num collatz(num x)
{
    return (x & 1) ? (3*x + 1) : (x/2);
}

那么collatz(x)的值只取决于x,而不取决于您何时调用它。(换句话说,collatz是一个纯函数。)因此,您可以为x的不同值存储collatz(x)的值。为此,可以使用std::map<num, num>std::unordered_map<num, num>

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

这是在科利鲁,计时(2.6秒)。