親和數問題學習筆記 調和級數和回溯演算法

2021-06-21 22:29:52 字數 2846 閱讀 3728

題目描述:

求500萬以內的所有親和數。

如果兩個數a和b的所有真因數之和等於b,b的所有真因數之和等於a,則稱a,b是一對親和數。

例如:220和284,1184和1210,2620和2924.

需要注意的是關於真因數的定義:出去整數本身之外的所有因子都稱作該整數的真因子,這裡是包括1的。

首先,對這篇學習筆記中參考到的前輩學習經驗的鏈結,置頂於正文。

july的博文中已經給出的解法,由於我目前對演算法的研究不是很深入,所以他解法中提到的一些用法還不是很理解,我再做一下詳細解釋。

要求n以內的所有親和數組合,我們就把n之類所有數的真因子都求出來,然後遍歷一遍有沒有滿足親和數條件的數。這樣解法的關鍵就在於如何在一定的複雜度之內把所有數的真因子都求出來。我們先把**給出,有個整體的認識:

#includeint sum[5000010];   //為防越界  

int main()

} for (i = 220; i <= n; i++) //掃瞄,o(n)。

} return 0;

}

這種解法的基本過程是:首先,我們先把所有sum都初始化為1,這個可以理解;然後,我們遍歷i的所有倍數,這些數由於是i的倍數,所以它們的真因子一定會包含i,故有了sum[j]+=i;這樣的語句,這裡需要注意的是,i沒有必要遍歷到n,因為最大的真因數是不會超過n/2的,這樣我們便可以得到所有數的真因子的和sum陣列。這裡還有乙個細節需要解釋一下,就是有的數會存在多個真因子,那麼每次遍歷的時候都會加上的,不會有遺漏。例如:6這個整數的真因子有2和3,那麼在遍歷2的倍數時,會有sum[6]+2的操作,在遍歷3的倍數的時候,又會有sum[6]+3的操作。對於那些只有乙個真因子的數,只需要加一次,而對於質數,就不要加了。

在得到sum這個陣列之後,我們就需要判斷了,滿足親和數條件的整數需要給出。判斷的條件有三個部分,sum[i]不能出界;去重;親和數條件。滿足條件的輸出了。

關於去重的條件,我們也可以輸出sum[i]==i;時候的情況,如下:

也就是說496和8128這兩個的真因子之和等於本身。

下面我們要詳細說一下這種演算法的複雜度。

顯然,這種解法包含兩個部分,乙個是求出sum陣列,乙個是判斷滿足親和數的條件。

1、求出sum陣列:我們需要遍歷所有小於n/2的i的倍數,那麼遍歷2的倍數的時候,我們需要遍歷n/2次,遍歷3的倍數,我們需要遍歷n/3次,這個是顯然的。那麼依次類推,遍歷到n/2的倍數的時候,我們需要遍歷n*(2/n)次,把它們相加就是乙個調和級數,即o(n/2*(1/2+1/3+...+2/n))。

對於調和級數的求和,有專門的研究資料。首先我們需要指出的是,調和級數是乙個發散的無窮級數,如下:

它們的求和趨向於無窮大,那麼為何在上july的博文中是ln(n)呢?原因是本題目的調和級數是部分求和,即n是乙個確切的數,而不是無窮大。對於確實範圍的調和級數求和確實是有界,證明如下:

上面的證明說明了,當n為無窮大的時候,調和級數確實是趨向於無窮大;當n是乙個確切的數的時候,為ln(k+1),那麼本題目中又不包括第乙個數,故這種情況下的調和級數之和就會趨向於ln(n)了。

這樣以後在分析複雜度的時候,再遇到這種的調和級數就沒有疑問了~

2、判斷

滿足親和數的條件:正常遍歷的複雜度為o(n)。

所以解法一的綜合複雜度為o(n*log(n)+n)=o(n*logn).

在解法一的注釋中提到了回溯法,下面我們再介紹一下回溯法:

尋找問題的解的一種可靠的方法是首先列出所有候選解,然後依次檢查每乙個,在檢查完所有或部分候選解後,即可找到所需要的解。

理論上,當候選解數量有限並且通過檢查所有或部分候選解能夠得到所需解時,上述方法是可行的。不過,在實際應用中,很少使用這種方法,因為候選解的數量通常都非常大(比如指數級,甚至是大數階乘),即便採用最快的計算機也只能解決規模很小的問題。

對候選解進行系統檢查的方法有多種,其中回溯和分枝定界法是比較常用的兩種方法。按照這兩種方法對候選解進行系統檢查通常會使問題的求解時間大大減少(無論對於最壞情形還是對於一般情形)。事實上,這些方法可以使我們避免對很大的候選解集合進行檢查,同時能夠保證演算法執行結束時可以找到所需要的解。因此,這些方法通常能夠用來求解規模很大的問題。

其實回溯演算法的應用有冪集問題、迷宮問題、n皇后問題。個人覺得迷宮問題的解法本質最能夠說明回溯演算法的思想本質。

計算機解迷宮時,通常用的是"試探和回溯"的方法,即從入口出發,順某一方向向前探索,若能走通,則繼續往前走;否則沿原路退回,換乙個方向再繼續探索,直至所有可能的通路都探索到為止,如果所有可能的通路都試探過,還是不能走到終點,那就說明該迷宮不存在從起點到終點的通道。

1.從入口進入迷宮之後,不管在迷宮的哪乙個位置上,都是先往東走,如果走得通就繼續往東走,如果在某個位置上往東走不通的話,就依次試探往南、往西和往北方向,從乙個走得通的方向繼續往前直到出口為止;

2.如果在某個位置上四個方向都走不通的話,就退回到前乙個位置,換乙個方向再試,如果這個位置已經沒有方向可試了就再退一步,如果所有已經走過的位置的四個方向都試探過了,一直退到起始點都沒有走通,那就說明這個迷宮根本不通;

所以說,回溯演算法的本質就是乙個先序遍歷一棵「狀態樹」的過程,只是這棵樹不是遍歷前就先建立的,而是隱含在遍歷過程中的一棵「狀態樹」。這方面的知識是**於資料結構!

解法2:質數線性篩法,這個方法比較數學,現在先不理解,日後再看。

問題 親和數

題目描述 古希臘數學家畢達哥拉斯在自然數研究中發現,220 的所有真約數 即不是自身的約數 之和為 1 2 4 5 10 11 20 22 44 55 110 284。而 284 的所有真約數為 1 2 4 71 142,加起來恰好為 220。人們對這樣的數感到很驚奇,並稱之為親和數。一般地講,如果...

親和數問題求解

在上面這個blog中看到不少比較經典的演算法問題研究,俗話說,好記性不如爛筆頭,所以記錄一下自己的理解,以防忘記 1首先,什麼是是親和數?親和數成對出現,假如a和b是一對親和數,那麼a的所有的真因子之和等於b,反過來b的所有真因子之和等於a 舉個栗子 220和284,一對最小的親和數 220的真因子...

調和數列問題

題目描述 演算法訓練 調和數列問題 時間限制 1.0s 記憶體限制 512.0mb 問題描述 輸入乙個實數x,求最小的n使得,1 2 1 3 1 4 1 n 1 x。輸入的實數x保證大於等於0.01,小於等於5.20,並且恰好有兩位小數。你的程式要能夠處理多組資料,即不停地讀入x,如果x不等於0.0...