Euler專案12 具有500個除數的三角數

2021-08-29 18:47:30 字數 3567 閱讀 8493

euler專案的

問題12的措辭與以前的問題有些不同。但是,正如我們將看到為該問題推導出有效的解決方案,我們可以使用與以前的一些問題非常相似的理論。問題在於

通過新增自然數生成三角數的序列。所以第7 個三角形數字是1 + 2 + 3 + 4 + 5 + 6 + 7 = 28.前十個術語是:

1,3,6,10,15,21,28,36,45,55 ......

讓我們列出前七個三角形數字的因子:

1:1

3:1,3

6:1,2,3,6

10:1,2,5,10

15:1,3,5,15

21:1,3,7,21

28:1,2, 4,7,14,28

我們可以看到28是第乙個有超過五個除數的三角形數。

擁有超過500個除數的第乙個三角形數的值是多少?

當我第一次閱讀問題描述時,我很快就看到了乙個直接的方法來找到問題的答案,我使用試驗除法來找到乙個數字的除數。這是我將在本博文中描述的第一種方法。之後,我將描述對解決方案策略的兩個修改以加速演算法。

審判部門非常直截了當。**的主要部分看起來像

int number = 0;

int i = 1;

while(numberofdivisors(number) < 500)

「智慧型」在於它所謂的numberofdivisors函式。該函式使用所有數字的試驗除法,包括原始數字的平方根。

該**看起來像

private int numberofdivisors(int number) 

}//correction if the number is a perfect square

if (sqrt * sqrt == number)

return nod;

}

我沒有太多理由去了解描述**的細節,因為它代表了自己。結果是

the first ******** number with over 500 divisors is: 76576500

solution took 214 ms

因此,雖然**易於閱讀,但執行起來並不是非常快。

現在我們已經建立了乙個找到答案的方法。問題是如何加快速度。很明顯,**的耗時部分是numberofdivisors函式。那麼讓我們看看我們是否可以改進它。

為了找到乙個有效的方法來推導出乙個數的除數,我們需要的屬性是基於我們在問題3中處理的數的素因子化。 任何數字n由其素因子化唯一地描述

其中p n是不同的素數,n是素數的指數,k是小於或等於n的平方根的所有素數的集合。採用任何素數因子的唯一組合並乘以它們,將產生n的唯一除數。這意味著我們可以使用組合學來確定基於素因子分解的除數的數量。素數p n可以選擇0,1,...,n次。這意味著在所有我們可以選擇p ñ在乙個ñ +1不同的方式。

n,d(n)的除數總數可表示為

現在我們只需要乙個函式來執行分解。

我們在問題3的解決方案中使用了素因子化,我將其修改為僅使用素數而不是奇數,並且我已經修改它以實際計算除數而不是返回除數。

**看起來像

private int primefactorisationnod(int number, int primelist) 

exponent = 1;

while (remain % primelist[i] == 0)

nod *= exponent;

//if there is no remainder, return the count

if (remain == 1)

}return nod;

}

它需要乙個素數列表,它從最低素數開始,並找到該素數的指數。正如在問題3中一樣,如果剩餘部分達到1,則沒有更多的除數,如果有剩餘部分,那麼剩下的也將是乙個素數除數。

在主迴圈中,我們還需要生成素數列表。這是使用問題10中開發的eratosthenes篩子完成的。隨著**行

int primelist = esieve(75000);

我不確定素數除數的上限,所以我試圖將它設定為75000,以便有乙個相當保守的界限。

使用素因子分解產生相同的結果,但明顯快於使用試驗**。

the first ******** number with over 500 divisors is: 76576500

solution took 16 ms

我們今天要處理的演算法的最後乙個改進是將問題分解為兩個較小的問題,這些問題明顯更容易解決。

在問題6中,我們確定了自然數的總和可以通過分析來編寫,這樣就可以了

其中n k是第k個三角形數。

我們將使用的屬性是k和k + 1是互質(我們在問題9中也處理過)。你可以使用歐幾里得的演算法在k的一般情況下說服你自己。

由於k和k + 1是互質的,這意味著它們的素數因子是不同的,並且

如果k是偶數,則d(n k)= d(k / 2)d(k + 1),如果k是奇數,則

d(n k)= d(k)d((k + 1)/ 2)。

在第一種情況下,如果k和k + 1是互逆的,則k / 2和k + 1也是如此,因為2將在k的素因子集中,因此不是k + 1。否則它們不會是互質的。因子分解的問題現在已被分為兩個較小數字的素數分解,這是一項非常容易的任務。

此外,如果我們編碼有點聰明,我們可以在後續迭代中重用k + 1的素因子化,因此我們只需要在每次迭代中分解乙個數。

我們已經實現的素數生成器和素因子化可以重複使用,但我們需要重新編寫主演算法。我選擇了乙個看起來像的實現

int number = 1;

int i = 2;

int cnt = 0;

int dn1 = 2;

int dn = 2;

int primelist = esieve(1000);

while (cnt < 500) else

i++;

}number = i * (i - 1) / 2;

根據解釋,**應該是相當自我解釋的。其中乙個更明顯的觀察結果是我已經明顯收緊了素數代的上限。

演算法的執行產生

the first ******** number with over 500 divisors is: 76576500

solution took 1 ms

對於具有500個除數的數字,沒有太大區別,但是我在1200除數時失去了對第二演算法的耐心。這個版本在超過5000的除數下仍能順利執行。因此,對於可伸縮性,最後乙個版本是乙個重大改進。

Actionscript 3 0具有正規表示式

正規表示式由一些普通字元和一些元字元 metacharacters 組成。普通字元包括大小寫的字母和數字,而元字元則具有特殊的含義,我們下面會給予解釋。在最簡單的情況下,乙個正規表示式看上去就是乙個普通的查詢串。例如,正規表示式 testing 中沒有包含任何元字元,它可以匹配 testing 和 ...

如何使得VC 6 0具有行號

程式設計時具有行號對程式設計過程有很打的幫助作用,特別在學習階段,能幫助我們提高程式可讀性,方便講解程式.但是如何使得vc中能夠具有行號,是值得我們去做的乙個問題。通過vc6linenumberaddin能夠解決這個問題,方法如下。二 解壓後把vc6linenumberaddin.dll拷貝到安裝路...

四元數對於SO3具有double cover的理解

本文是在學習 quaternion kinematics for the error state kalman filter 時,對於書中四元數double cover特性的個人理解。作者在文中也有說明,該現象仍未有乙個完美的解釋,本文的內容包含很多猜想的成分,並不嚴謹,僅提供乙個理解的思路 我們知...