陷入无限循环? (也许)

时间:2014-10-24 21:39:24

标签: c++ collatz

我正在尝试用c ++完成Project Euler Problem 14,老实说我被困住了。现在,当我运行问题时,它会停留在So Far:计数最高的数字: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个术语。   虽然尚未证实(Collat​​z问题),但确实如此   以为所有起始编号都以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 %d\n",
                     number, count );
        if( highCount < count ) {
            highCount = count;
            highNum = number;
        }
        count = 0;
        //break;
    }
    printf( "The number with the highest count: %d with the count of %d\n",
            highNum, highCount );
}

4 个答案:

答案 0 :(得分:3)

您正在获得整数溢出。像这样更新您的代码并自己查看:

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的类型更改为long longunsigned long long以防止溢出。

(是的,缓存中间结果)

答案 1 :(得分:3)

记住所有中间结果(最高可达一些) 另外,使用足够大的类型:

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

关于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位来表示无符号数。

答案 2 :(得分:0)

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

类似的东西:

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

Demo(10秒)

答案 3 :(得分:0)

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

鉴于

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,而不是取决于您何时调用它。 (换句话说,collatzpure function。因此,对于collatz(x)的不同值,您可以memoize x的值std::map<num, num>。为此,您可以使用std::unordered_map<num, num>或{{1}}。

作为参考,here是完整的解决方案。

这里是Coliru,时间(2.6秒)。