我正在尝试用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个术语。 虽然尚未证实(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 %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 );
}
答案 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 long
或unsigned 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
,而不是取决于您何时调用它。 (换句话说,collatz
是pure function。因此,对于collatz(x)
的不同值,您可以memoize x
的值std::map<num, num>
。为此,您可以使用std::unordered_map<num, num>
或{{1}}。
作为参考,here是完整的解决方案。
这里是Coliru,时间(2.6秒)。