【问题标题】:memoization should have worked记忆应该有效
【发布时间】:2020-08-22 17:45:26
【问题描述】:

没有记忆这个Euler Project 14 的解决方案可以正常工作!然后通过记忆,它应该工作得更快......但它几乎停在i = 1818 或附近。多么奇怪!很难理解有什么问题!你能帮忙吗?

#include <stdio.h>

#define limit 1000000

int arr[limit];

int fun(long long int i) {
    long long int count = 1;
    long long int num;
    arr[limit];
    num = i;
    while (num > 1) {
        if (arr[num] != NULL) {
            count = count - 1 + arr[num];
            break;
        }
        if (num % 2 == 0) {
            num = num / 2;
            count++;
        } else {
            num = 3 * num + 1;
            count++;
        }
    }
    arr[i] = count;
    return count;
}

int main() {
    long long int i;
    for (i = 2; i < limit; i++) {
        long long int count = fun(i);
        printf("d %lld c: %lld\n", i, count);
    }
    return 0;
}

【问题讨论】:

  • arr[] 声明为static 数组,否则每次到达return 语句时它都会消失。如果你想要合理的结果,你也应该初始化它。
  • 您的函数fun 返回一个int,那么为什么将它存储在long long int 中呢?这样做没有任何好处。如果它不适合int,那么返回值将是错误的,你用它做什么都没关系。可能您希望该函数返回 long long int,但您声明它是错误的。
  • @r3mainer arr 似乎是全局的,因此具有静态存储。函数内部arr[limit];的实例是一个无用的语句,充其量什么都不做。
  • @TomKarzes 啊,你是对的。
  • num 可以高于 10^6。那么arr[num] 会导致未定义的行为

标签: c algorithm dynamic computer-science memoization


【解决方案1】:

好的,我认为您的代码的主要问题是 Collat​​z 序列可以为您提供的数字比您在下降到 1 之前开始的数字高很多。根据Project Euler 14,你应该找到低于 1000000 的起始数字,它会在达到零之前产生最长的链。但是从 1819 年开始的 Collat​​z 数列包括大于一百万的数字。因此,您正试图访问超出范围的 arr[] 元素。

此外,正如 cmets 中所指出的,arr[limit]; 函数中的声明 fun() 没有任何用处。如果您在编译器中启用了警告,它可能会标记这一点,以及将void* 指针与整数进行比较的语句if(arr[num]!=NULL)

如果您将while() 块的第一条语句替换为if (num &lt; limit &amp;&amp; arr[num]!=NULL),那么您至少应该避免分段错误。

您的main() 函数需要重写以找到产生最长链的起始数字,而不是仅仅打印一百万行数据。

如果您愿意,可以尝试运行它:

#include <stdio.h>

#define LIMIT 1000000

int arr[LIMIT] = { 0 };

long fun(long i) {
    long count = 1;
    long num;
    num = i;
    while (num > 1) {
        if (num < LIMIT && arr[num] != 0) {
            count = count - 1 + arr[num];
            break;
        }
        if (num % 2 == 0) {
            num = num / 2;
            count++;
        }
        else {
            num = 3 * num + 1;
            count++;
        }
    }
    arr[i] = count;
    return count;
}

int main(){
    long i, longest=0, maxstart;
    for (i=2; i<LIMIT; i++) {
        long count = fun(i);
        if (count > longest) {
            longest = count;
            maxstart = i;
        }
    }
    printf("%ld\n",maxstart);
    return 0;
}

【讨论】:

  • 问题陈述甚至指出了这一点 - 注意:一旦链启动,条款允许超过一百万。
  • @r3mainer 天哪!你解释得很好,太棒了!现在代码运行得非常快......!虽然这不是我对 Eu14 问题的完整解决方案......但我把所有东西都搞砸了并编辑了所有东西,只是为了得到我昨天学到的 Memoization 的输出......非常感谢......花时间并指出我的问题!我真的很感激。
猜你喜欢
  • 2023-03-04
  • 2010-12-23
  • 1970-01-01
  • 1970-01-01
  • 2011-03-14
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多