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

 

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值