[Project Euler] 来做欧拉项目练习题吧: 题目014

                                           [Project Euler] 来做欧拉项目练习题吧: 题目014

                                                                  周银辉 

 

问题描述

The following iterative sequence is defined for the set of positive integers:

n --> n/2 (n is even)
n --> 3n + 1 (n is odd)

Using the rule above and starting with 13, we generate the following sequence:

13 --> 40 --> 20 --> 10 --> 5 --> 16 --> 8 --> 4 --> 2 --> 1

It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 1.

Which starting number, under one million, produces the longest chain?

NOTE: Once the chain starts the terms are allowed to go above one million. 

 

问题分析:

在小于1000000的数中,哪个数作为首项并按如下公式能得到最长的数列:

n --> n/2 (n is even)

n --> 3n + 1 (n is odd)

根据n判断其构成的数列长度,如果n比较小的话,则简单地写个递归函数就可以了。

但对于一百万这样的大数据,递归一百万次效率很低下,并且可能堆栈溢出。

所以,为了减少递归次数,用一个缓冲区来保存中间结果,比如我们已经计算过13的话,在计算26时,其除以2等于13,

然后我们可以直接从缓冲区中取13上次的计算结果。

另外在缓冲区中取值时有一个技巧:我们应该在递归前判断缓冲区中是否有值,如果有则不递归,而不应该在递归后才判断缓冲区是否有值(如果有则立即返回)。前者递归函数要调用132434424次,时间上约30秒,后者调用3168610次,时间上1秒多。

设置的缓冲区在递归算法中经常用到,就如许多动态规划题目一样 

 

 

std::hash_map<long, long> buffer;
long  get_chain_length(long n)
{
long length=0, next;
std::hash_map<long, long>::iterator found;
if(n==1)
{
length = 1;
}
else 
{
next = n%2==0? n>>1 : n*3+1;
found = buffer.find(n);
if(found != buffer.end())
{
length = found->second; 
}
else
{
length = 1+ get_chain_length(next);
buffer[n] = length;
}
}
return length;
}

 

  

posted @ 2011-02-20 21:02 周银辉 阅读(1419) 评论(6) 编辑 收藏

 回复 引用 查看   
#1楼 2011-02-20 21:22 yzx226      
结果,n是多少?
 回复 引用 查看   
#2楼 2011-02-21 15:40 fluxay      
这个问题完全用不着递归写啊,迭代写起来很方便的.
 回复 引用 查看   
#3楼 2011-02-21 15:58 fluxay      
哦,迭代不方便.
 回复 引用 查看   
#4楼[楼主] 2011-02-21 16:03 周银辉      
@fluxay
呵呵呵....

 回复 引用 查看   
#5楼 2011-02-24 09:55 RealDigit      
完全没看懂
 回复 引用 查看   
#6楼 2011-03-04 16:08 玫瑰季节      
用一个数组,保存已经计算的结果,

假设这个过程用函数f(n)描述,

则对于特定的n0 如果, f(n0)已被计算出来了,则L(n) = L(f(n0)) + 1;

如果,n0是通过N次计算,到达nk(已获得解答), 则L(n0) = L(nk) + N

当然,这里面,还需要考虑到超过one million的处理,



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1959248 KNnTMn8vDBQ=