项目EULER#29

时间:2010-01-27 14:41:16

标签: c++ algorithm math

好吧,在通过天真的STL集解决了这个problem后,我正在阅读论坛条目,在那里我找到了这个条目:

 #include <iostream>   
 #include <cmath> 
 #define MAX 100
 using namespace std;

 int main(){
    int res=(MAX-1)*(MAX-1);
    for(int i=2;i<MAX;i++)
        for(int j=i*i;j<=MAX;j=j*i)
            res = res-int(MAX*(log(i)/log(j)))+1;
     cout<<res<<endl;
     return 0;
  }

作者的解释: Maximum will be 99*99. I subtracted occurrences of those numbers which are powers of some lower numbers (2-100): - For example: - 4^2,4^3,4^4 (i.e. 3 should be subtracted) as they will be duplicates from lower number powers as in 2^4,2^6,2^8

这个程序给出了正确答案check here,但我无法得到实施的逻辑,准确地说,我没有得到如何确定重复项。有人可以帮忙吗?

4 个答案:

答案 0 :(得分:14)

我可能会遗漏一些东西,但在我看来,这个程序给出了错误的答案。一个接一个。如果我将MAX设置为10,则会将其设置为2。

我已经读过一些玩家想要产生大致的答案,然后对Project Euler服务器进行字典攻击以强制解决问题。其他玩家则认为这违背了事物的精神。

无论如何 - 像这样的算法(从N * M开始并消除重复)是解决问题的正确方法,但正如所写,这段代码对我来说没有多大意义。请注意,在任何情况下int(MAX*(log(i)/log(j)))对舍入误差都非常敏感;但即使你通过使用整数运算消除了这个错误源,程序仍然会给出错误的答案。

编辑:我们如何(正确)计算重复数?

首先,您必须明白,如果两个数字具有相同的素数因子分解,则它们只相同。所以只有重复 a 1 b 1 = 2 b 2 a 1时 a 2 是同一整数的不同整数幂,我称之为 x 。例如,

  • 9 7 = 3 14 ;这是可能的,因为9和3都是3的幂。
  • 8 6 = 4 9 ;这是可能的,因为8和4都是2的幂。

所以我们已经确定了对于所有重复项, a 1 = x e 1 a 2 = x e 2 表示某些整数 x e 1 e 1

然后用一点代数,

  

a 1 b 1 = a <子> 2 b'/ EM> <子> 2

     

X ë <子> 1 B'/ EM> <子> 1 = x e 2 b 2

     

e 1 b 1 = e 2 b'/ EM> <子> 2

回到前面的例子,

  • 9 7 = 3 14 因为2×7 = 1×14。
  • 8 6 = 4 9 因为3×6 = 2×9。

因此,要查找任何给定 x 的所有重复项,您只需要找到更简单的表达式 eb 的重复项,其中2≤ x < sup> e ≤100且2≤ b ≤100。

这是一个更简单问题的图片, x = 3且 b 的范围仅为2到10.我已经标记了两个有重复的地方。

e=1  a=3    *********
e=2  a=9      * * * * * * * * *
e=3  a=27       *  *  *  *  *  *  *  *  *
e=4  a=81         *   *   *   *   *   *   *   *   *
                  |               |
        1*8 = 2*4 =  4*2         3*8 = 4*6
        3^8 = 9^4 = 81^2        27^8 = 81^6

以下是重复:

e=1  a=3    *********
e=2  a=9      x x x x * * * * *
e=3  a=27       x  x  x  *  x  *  *  *  *
e=4  a=81         x   x   x   x   x   *   *   *   *

您找到的C ++程序试图通过访问每对重叠的行i和j来计算它们,并计算行i与行j重叠的程度。但同样,除非我遗漏了一些东西,否则这个程序似乎无可救药。它完全错过了一些行(你从来没有i = 9和j = 27,或者i = 27和j = 81)。

答案 1 :(得分:0)

有(至少)两种方法来解决这个问题。一种是在0处开始计算不同的值,并为之前未见过的每个计算值添加一个。另一种方法是计算最大值数,然后为每个副本减去一个。

海报正在尝试第二次演出。对于99个值,a的范围可以是2到100,b也可以,因此有99 * 99个生成的值。然后海报会尝试减去重复的值以获得正确的答案。

编辑:但是,海报写的算法不正确。 例如,设置MAX = 89。对于8,它应该44,但它会45。对于9,它应该提供54,但会提供56。要么他们运气好又发生在一个算法上,这个算法给出了一些输入的正确答案,或者他们反向设计了一个算法,该算法在MAX = 100时起作用,但对所有其他值都不起作用。

答案 2 :(得分:0)

首先,它在第6行将res设置为99 * 99,因为MAX定义为100.然后它进入循环,条件是i小于MAX 。然后它进入这个伪代码循环

int i;
int j;
int x=2;

for(j = i 2 ; j <= MAX,j = i x
{
  res = res-(MAX *( j log(i))+1;
  X ++;
}

抱歉'回合上面没有使用<pre><code>;但如果我这样做,我就无法使用<sup>

请注意log(a)/log(x) x log(a)相同


对问题的评论,因为<sup>在那里不起作用:

2 log(2)= 1因为2 1 = 2
2 log(4)= 2因为2 2 = 2
log(x)== 10 log(x)
log(10)= 1

g log(x)= y =&gt; g y = x

答案 3 :(得分:0)

嗯,问题涉及组合从一个范围中选择的两个数字的方法。有99个可能的数字,因此组合的数量是99 * 99,可能有重复。他的基本算法是确定存在多少重复项,然后从最大值中减去该值。

至于计算重复数,可以直观地根据其主要因素来考虑数字。将数字提升为整数幂意味着将其乘以自身;因此,表示为素数列表,这相当于简单地连接列表。例如,6是{2,3},因此6 ^ 3将是{2,2,2,3,3,3}。请注意,如果计算每个素数出现在列表中的次数,则x ^ n将始终具有与x相同的比例,例如6 ^ n将具有等量的2和3。因此,在素数之间具有相同比例的范围内的任何两个数字必须都是某个数的幂。

因此,在完整列表中,每个不同比例的素因子将重复出现为x ^ 2,x ^ 3,x ^ 4 ...,(x ^ 3)^ 2,(x ^ 3)^ 4 ...,(x ^ 4)^ 2 ......等,其中x是该比例的最小数字;更准确地说,(x ^ m)^ n其中(x ^ m)&lt; = 100且2&lt; = n&lt; = 100.因为(x ^ m)^ n等于x ^(m n ),计算重复数量相当于计算x ^(m n)也可以<= 100的方式。