• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 200, comments - 8, trackbacks - 0, articles - 0

            作者:上善若水、July、yansha。
            出處:http://blog.csdn.net/v_JULY_v 


            前奏
                本章陸續開始,除了繼續保持原有的字符串、數組等面試題之外,會有意識的間斷性節選一些有關數字趣味小而巧的面試題目,重在突出思路的“巧”,和“妙”。本章親和數問題之關鍵字,“500萬”,“線性復雜度”。

             

            第一節、親和數問題
            題目描述:
            求500萬以內的所有親和數
            如果兩個數a和b,a的所有真因數之和等于b,b的所有真因數之和等于a,則稱a,b是一對親和數。
            例如220和284,1184和1210,2620和2924。

            分析:
                首先得明確到底是什么是親和數?

            親和數問題最早是由畢達哥拉斯學派發現和研究的。他們在研究數字的規律的時候發現有以下性質特點的兩個數:
            220的真因子是:1、2、4、5、10、11、20、22、44、55、110;
            284的真因子是:1、2、4、71、142。
            而這兩個數恰恰等于對方的真因子各自加起來的和(sum[i]表示數i 的各個真因子的和),即
            220=1+2+4+71+142=sum[284],
            284=1+2+4+5+10+11+20+22+44+55+110=sum[220]。
            得284的真因子之和sum[284]=220,且220的真因子之和sum[220]=284,即有sum[220]=sum[sum[284]]=284。

            如此,是否已看出絲毫端倪?

            如上所示,考慮到1是每個整數的因子,把出去整數本身之外的所有因子叫做這個數的“真因子”。如果兩個整數,其中每一個真因子的和都恰好等于另一個數,那么這兩個數,就構成一對“親和數”(有關親和數的更多討論,可參考這:http://t.cn/hesH09)。

             

            求解:
                了解了什么是親和數,接下來咱們一步一步來解決上面提出的問題(以下內容大部引自水的原話,同時水哥有一句原話,“在你真正弄弄懂這個范例之前,你不配說你懂數據結構和算法”)。

            1. 看到這個問題后,第一想法是什么?模擬搜索+剪枝?回溯?時間復雜度有多大?其中bn為an的偽親和數,即bn是an的真因數之和大約是多少?至少是10^13(@iicup:N^1.5 對于5*10^6 , 次數大致 10^10 而不是 10^13.)的數量級的。那么對于每秒千萬次運算的計算機來說,大概在1000多天也就是3年內就可以搞定了(iicup的計算: 10^13 / 10^7 =1000000(秒) 大約 278 小時. )。如果是基于這個基數在優化,你無法在一天內得到結果的。
            2. 一個不錯的算法應該在半小時之內搞定這個問題,當然這樣的算法有很多。節約時間的做法是可以生成伴隨數組,也就是空間換時間,但是那樣,空間代價太大,因為數據規模龐大。
            3. 在稍后的算法中,依然使用的伴隨數組,只不過,因為題目的特殊性,只是它方便和巧妙地利用了下標作為伴隨數組,來節約時間。同時,將回溯的思想換成遞推的思想(預處理數組的時間復雜度為logN(調和級數)*N,掃描數組的時間復雜度為線性O(N)。所以,總的時間復雜度為O(N*logN+N)(其中logN為調和級數)  )。


            第二節、伴隨數組線性遍歷
            依據上文中的第3點思路,編寫如下代碼:

            int sum[5000010];   //為防越界  
              
            int main()   
            {  
                
            int i, j;  
                
            for (i = 0; i <= 5000000; i++)   
                    sum[i] 
            = 1;  //1是所有數的真因數所以全部置1  
                  
                
            for (i = 2; i + i <= 5000000; i++)    
                {    
                    
            //5000000以下最大的真因數是不超過它的一半的  
                    j = i + i;  //因為真因數,所以不能算本身,所以從它的2倍開始  
                    while (j <= 5000000)   
                    {    
                        
            //將所有i的倍數的位置上加i  
                        sum[j] += i;    
                        j 
            += i;       
                    }  
                }  
                  
                
            for (i = 220; i <= 5000000; i++)   //掃描,O(N)。  
                {  
                    
            // 一次遍歷,因為知道最小是220和284因此從220開始  
                    if (sum[i] > i && sum[i] <= 5000000 && sum[sum[i]] == i)  
                    {  
                        
            //去重,不越界,滿足親和  
                        printf("%d %d/n",i,sum[i]);  
                    }  
                }  
                
            return 0;  
            }  

            第三節、程序的構造與解釋
                我再來具體解釋下上述程序的原理,ok,舉個例子,假設是求10以內的親和數,求解步驟如下:

            因為所有數的真因數都包含1,所以,先在各個數的下方全部置1

            1. 然后取i=2,3,4,5(i<=10/2),j依次對應的位置為j=(4、6、8、10),(6、9),(8),(10)各數所對應的位置。
            2. 依據j所找到的位置,在j所指的各個數的下面加上各個真因子i(i=2、3、4、5)。
              整個過程,即如下圖所示(如sum[6]=1+2+3=6,sum[10]=1+2+5=8.):
              1  2  3  4  5  6  7  8  9  10
              1  1  1  1  1  1  1  1  1  1
                         2      2      2      2
                                 3          3 
                                         4
                                                 5
            3. 然后一次遍歷i從220開始到5000000,i每遍歷一個數后,
              將i對應的數下面的各個真因子加起來得到一個和sum[i],如果這個和sum[i]==某個i’,且sum[i‘]=i,
              那么這兩個數i和i’,即為一對親和數。
            4. i=2;sum[4]+=2,sum[6]+=2,sum[8]+=2,sum[10]+=2,sum[12]+=2...
              i=3,sum[6]+=3,sum[9]+=3...
              ......
            5. i=220時,sum[220]=284,i=284時,sum[284]=220;即sum[220]=sum[sum[284]]=284,
              得出220與284是一對親和數。所以,最終輸出220、284,...



            狠狠色噜噜色狠狠狠综合久久| 久久精品国产精品亜洲毛片| 久久久国产视频| 久久久久无码精品国产| 精品久久8x国产免费观看| 国产Av激情久久无码天堂| 国产精品激情综合久久| 久久精品视频一| 亚洲国产成人久久精品动漫| 色欲综合久久躁天天躁| 欧美熟妇另类久久久久久不卡 | 亚洲中文字幕久久精品无码APP| 日产精品久久久一区二区| 国产真实乱对白精彩久久| 久久久国产精华液| 精品久久人人做人人爽综合 | 久久精品国产亚洲AV不卡| 久久久久青草线蕉综合超碰| 久久电影网一区| 热久久最新网站获取| 国产综合免费精品久久久| 亚洲人成网亚洲欧洲无码久久 | 久久综合给合综合久久| 久久精品国产亚洲AV电影| 久久久精品国产亚洲成人满18免费网站 | 久久婷婷五月综合97色直播| 麻豆一区二区99久久久久| 久久久精品波多野结衣| 亚洲精品tv久久久久久久久| 精品视频久久久久| 久久综合久久综合久久| 99久久精品国内| 久久精品国产亚洲av高清漫画| 国产毛片欧美毛片久久久| 亚洲人成无码久久电影网站| 久久久久国产精品三级网| 国产A级毛片久久久精品毛片| 青青青国产精品国产精品久久久久| 久久精品www人人爽人人| 久久久久久久亚洲Av无码| 久久综合亚洲欧美成人|