题目
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.
分析思路
- 由于一个确定的整数在题目的规则下一定也会经历唯一确定步数,所以没有必要每个整数都从头到尾重新计算一遍
- 将中间的计算结果保存下来,减少后续的重新计算,这种技巧常常被用在搜索算法中,常被叫做“记忆化搜索”
代码如下
两种不同方法的对比
普通方法(暴力求解),时间复杂度高
#include<stdio.h>
#define max_n 1000000
long long get_len(long long x) {
if (x == 1) return 1;
if (x & 1) return get_len(3 * x + 1) + 1;
return get_len(x >> 1) + 1;
}
int main() {
int ans = 0, num = 0;
for (int i = 2; i < max_n; ++i) {
int l = get_len(i);
if (l > ans) ans = l , num = i;
}
printf("%d\n", num);
return 0;
}
记忆化搜索方法,时间复杂度低
#include<stdio.h>
#define max_n 1000000
#define keep_max_length 1000000
int keep[keep_max_length] = {0};
long long get_len(long long x) {
if (x == 1) return 1;
if (x < keep_max_length && keep[x]) return keep[x];
int ret;
if (x & 1) ret = get_len(3 * x + 1) + 1;
else ret = get_len(x >> 1) + 1;
if (x < keep_max_length) keep[x] = ret;
return ret;
}
int main() {
int ans = 0, num = 0;
for (int i = 2; i < max_n; ++i) {
int l = get_len(i);
if (l > ans) ans = l , num = i;
}
printf("%d\n", num);
return 0;
}