【问题标题】:Project Euler 5欧拉计划 5
【发布时间】:2011-12-27 13:43:48
【问题描述】:

2520 是可以除以 1 到 10 的每个数字而没有余数的最小数字。

能被 1 到 20 的所有数整除的最小正数是多少?

我的解决方案:

#include<stdio.h>
int gcd(int m, int n);
int lcm(int a, int b);
int main()
{
    int x=1, i;
    for(i=1; i<20; i++)
    {
        x=lcm(x, i+1);
    }
    printf("The answer is:\t%d", x);
    return 0;
}

int gcd(int m, int n)
{
    while(m!=n)
    {
        if(m>n)
        m=m-n;
        else
        n=n-m;
    }
    return m;
}

int lcm(int a, int b)
{
    return ((a*b)/gcd(a, b));
}

请告诉我哪里错了?它在运行时只显示空白屏幕。

【问题讨论】:

  • 当您添加额外的打印语句时,您学到了什么?
  • 我在哪里添加了额外的打印语句?
  • 他说你应该缩小你卡住的地方。
  • 好的.. 但我应该怎么做呢?我试图搜索我能找到的每一个错误。它现在甚至可以运行,但给出了错误的答案。
  • 案例20:232792560需要int64

标签: c


【解决方案1】:

Project Euler 中的大多数问题都可以通过三种方式解决:

  • 使用蛮力
  • 使用解决更普遍问题的算法(就像您一样)
  • 智能解决方案最多需要铅笔和纸

如果您对一个好的解决方案感兴趣而不是修复您的代码,请尝试专注于最后一种方法:

诀窍是找到最小的素数多重集,使得 1 到 20 之间的任何数字都可以表示为其中一些素数的乘积。

1 = 1      11 = 11
2 = 2      12 = 2*2*3
3 = 3      13 = 13
4 = 2*2    14 = 2*7
5 = 5      15 = 3*5
6 = 2*3    16 = 2*2*2*2
7 = 7      17 = 17
8 = 2*2*2  18 = 2*3*3
9 = 3*3    19 = 19
10 = 2*5   20 = 2*2*5

通过对 1 到 10 之间的数字进行“或”运算,我们得到 1*2*2*2*3*3*5*7,正如预期的那样,恰好是 2520。

现在如果我们从 1 到 20,我们得到 1*2*2*2*2*3*3*5*7*11*13*17*19,这确实被 Project Euler 接受了。

【讨论】:

  • 好吧..我猜,你想说我应该找到低于 20 的素数并使用素数分解,我应该计算 lcm,这应该是答案..我是对的吗?
  • 我编辑了我的帖子以更清楚我的意思。忘记 lcm,诀窍是利用素数分解。
  • Amit:将 1 到 20 之间的数中的质因数依次添加到我们的结果多重集中,但只添加那些尚未在多重集中的质因数。
【解决方案2】:

如果你应该从这个练习中只学到一个教训,那就这样吧:你做乘法和除法的顺序很重要

即使它在数学中无关紧要,它在你的程序中也很重要。例如,在数学中(a*b)/gcd(a, b)a/gcd(a, b)*b 之间没有区别;在你的程序中,它会决定通过和失败。

(P.S. 当然,您也需要修复逻辑中的错误:您不应该将 x 乘以 lcm)。

编辑

要了解此处的顺序为何如此不同,请考虑计算 lcm23279256020232792560 可以被20 整除,所以它是lcm。但是,当您计算232792560*20 时,会出现溢出;然后你除以20,但你没有得到232792560

由于除数是gcd(a,b),您可以在乘以b 之前将其从a 中除掉,而不会通过整数除法截断结果。这个经验丰富的程序员不假思索地使用的小技巧可以为您节省数小时的调试时间。

【讨论】:

  • 是的。我明白这一点,但我想括号放在我的代码中。
  • @Amit:如果 (a*b) 溢出 int 数据类型,则不会。
  • 我应该把它们放在哪里?我的代码中哪个括号放错了?
  • @AmitTiwari lcm 的返回应该是a/gcd(a, b)*b
  • 哦..谢谢。这是一个非常好的建议和概念,我绕过了。
【解决方案3】:

printf() 会告诉您您的代码正在进入无限循环。我在while 循环的gcd() 中添加了一个printf()

    n=n-m;
    printf("m=%d n=%d\n", m, n); 
}   
return m;

while(m!=n) 永远不会对 n=14 成立。最后mn 溢出,因为x 达到了int 类型无法容纳的更高数字!

【讨论】:

    【解决方案4】:

    错误是x*=lcm(x, i+1);,这是完整的解决方案,

    long gcd(long m, long n);
    long lcm(long a, long b);
    
    int main()
    {
        long x=1;
        for(int i=2; i<=20; i++)
        {
            x=lcm(x,i);
        }
        cout << "The answer is: " << x << endl;
        return 0;
    }
    
    long gcd(long a, long b)
    {
            return (b==0)?a:gcd(b,a%b);
    }
    
    long lcm(long a, long b)
    {
        return ((a*b)/gcd(a, b));
    }
    

    【讨论】:

    • 和 18044195 不是正确答案。并且您不能在 for 循环中声明 i 很长。
    • printf() 中提到的long 的格式说明符不正确! .. 对于正确的格式说明符,请检查 printf() 手册页或 here
    【解决方案5】:

    n-1 应该是 n;并且 x =lcm(...) 而不是 x*=lcm(...)。但我不太清楚(远离终端)你的循环在哪里卡住了。

    【讨论】:

    • 好的.. 我修复了上述错误.. 答案是 18044195。但是,这不是正确的答案。
    【解决方案6】:

    20 的答案是:232792560。

    这些都是答案适合长整数的所有数字的答案:

    1 : 1
    2 : 2
    3 : 6
    4 : 12
    5 : 60
    6 : 60
    7 : 420
    8 : 840
    9 : 2520
    10 : 2520 11 : 27720
    12 : 27720
    13 : 360360 14 : 360360 15 : 360360 16 : 720720
    17 : 12252240
    18 : 12252240
    19 : 232792560
    20 : 232792560 21 : 232792560
    22 : 232792560
    23 : 5354228880
    24 : 5354228880
    25 : 26771144400
    26 : 26771144400
    27 : 80313433200
    28 : 80313433200
    29 : 2329089562800
    30 : 2329089562800
    31 : 72201776446800
    32 : 144403552893600
    33 : 144403552893600
    34 : 144403552893600
    35 : 144403552893600
    36 : 144403552893600
    37 : 5342931457063200
    38 : 5342931457063200
    39 : 5342931457063200
    40 : 5342931457063200
    41 : 219060189739591200
    42 : 219060189739591200

    【讨论】:

      【解决方案7】:

      根本不需要为此编写程序。我的解决方案:

      写下所有不大于最大可除数的素数。

      对于 20,其:2、3、5、7、11、13、17、19。

      然后,如果任何素数的平方根不大于最大可除数(本例中为 20),则将原始素数替换为其平方根。

      在本例中 2*2 > 20, 2*2*2 > 20, 2*2*2*2 > 20, 但 2*2*2*2*2 2*2*2*2 = 16 所以新的数线是:
      16、3、5、7、11、13、17、19。

      3 相同:3*3 > 20 但 3*3*3 20,所以这是最后一行。

      将所有数字相乘,你会得到答案:16 * 9 * 5 * 7 * 11 * 13 * 17 * 19 = 232,792,560

      【讨论】:

      • 这不是和菲利普的回答一样吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多