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.
为正整数集定义以下迭代序列:
n → n / 2(n为偶数)n →3 n + 1(n为奇数)
使用上面的规则并从13开始,我们生成以下序列:
13→40→20→10→5→16→8→4→2→1
可以看出,该序列(从13开始并在1结束)包含10个项。虽然尚未证实(Collatz问题),但认为所有起始数字都是1。
哪个起始编号低于一百万,产生最长的链?
注意:一旦链条启动允许超过一百万。
思路
1.递归求解法
(1)求每个数字的数字链长度,考虑边界条件num == 1是求到链的终点,否则返回相应的算式链并+1
(2)从1遍历到max的,不断更新ans和ans_len;
用时:3475ms
#include <stdio.h>
#include <inttypes.h>
#define max 1000000
int clain_len(int64_t num){
if(num == 1) return 1;
if(num % 2 == 0){
return clain_len(num / 2) + 1;
}else {
return clain_len(num * 3 + 1) + 1;
}
}
int main(){
int ans = 0;
int ans_len = 0;
for(int i = 1; i < max; i++){
int store = clain_len(i);
if(ans_len < store){
ans_len = store;
ans = i;
}
}
printf("%d %d\n", ans_len, ans);
return 0;
}
2.记忆化求解法
1.记忆化:我们可以发现5->16->8->4->2->1链的长度为6;
10->5->16->8->4->2->1链的长度为7,实际上把链重新遍历了一遍
这里我们建立一个数组keep来存储遍历过的链长,这样再次查找的时候就不用多次递归调用以节省时间
用时:125ms
#include <stdio.h>
#include <inttypes.h>
#define max 1000000
#define keep_max 5000000
int keep[keep_max + 5] = {0};
int clain_len(int64_t num){
int ans_len = 0;
if(num == 1) return 1;
if(num <= keep_max && keep[num]){
return keep[num];
}else{
if(num % 2 == 0){
ans_len = clain_len(num / 2) + 1;
}else {
ans_len = clain_len(num * 3 + 1) + 1;
}
}
if(num < keep_max){
keep[num] = ans_len;
}
return ans_len;
}
int main(){
int ans = 0;
int ans_len = 0;
for(int i = 1; i < max; i++){
int store = clain_len(i);
if(ans_len < store){
ans_len = store;
ans = i;
}
}
printf("%d %d\n", ans_len, ans);
return 0;
}