`
shangjava
  • 浏览: 1233132 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

亲和数问题

阅读更多

第一节、亲和数问题
题目描述:
求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是每个整数的因子,把出去整数本身之外的所有因子叫做这个数的“真因子”。如果两个整数,其中每一个真因子的和都恰好等于另一个数,那么这两个数,就构成一对“亲和数”

求解:
    了解了什么是亲和数,接下来咱们一步一步来解决上面提出的问题(以下内容大部引自水的原话)。

  1. 看到这个问题后,第一想法是什么?模拟搜索+剪枝?回溯?时间复杂度有多大?其中bn为an的伪亲和数,即bn是an的真因数之和大约是多少?至 少是10^13的数量级的。那么对于每秒千万次运算的计算机来说,大概在1000多天也就是3年内就可以搞定了。如果是基于这个基数在优化,你无法在一天 内得到结果的。
  2. 一个不错的算法应该在半小时之内搞定这个问题,当然这样的算法有很多。节约时间的做法是可以生成伴随数组,也就是空间换时间,但是那样,空间代价太大,因为数据规模庞大。
  3. 在稍后的算法中,依然使用的伴随数组,只不过,因为题目的特殊性,只是它方便和巧妙地利用了下标作为伴随数组,来节约时间。同时,将回溯的思想换成递推的思想(预处理数组的时间复杂度为logN(调和级数)*N,扫描数组的时间复杂度为线性O(N)。所以,总的时间复杂度为O(N*logN+N)(其中logN为调和级数)   )。


第二节、伴随数组线性遍历
依据上文中的第3点思路,编写如下代码:


  1. //求解亲和数问题   
  2.   
  3. //第一个for和第二个for循环是logn(调和级数)*N次遍历,第三个for循环扫描O(N)。   
  4. //所以总的时间复杂度为 O(n*logn)+O(n)=O(N*logN)(其中logN为调和级数)。   
  5.   
  6. //关于第一个for和第二个for寻找中,调和级数的说明:   
  7. //比如给2的倍数加2,那么应该是  n/2次,3的倍数加3 应该是 n/3次,...   
  8. //那么其实就是n*(1+1/2+1/3+1/4+...1/(n/2))=n*(调和级数)=n*logn。   
  9.   
  10. //copyright@ 上善若水   
  11. //July、updated,2011.05.24。   
  12. #include<stdio.h>   
  13.   
  14. int  sum[5000000];   
  15.   
  16. int  main()   
  17. {  
  18.     int  i, j;  
  19.     for  (i = 0; i <= 5000000; i++)   
  20.         sum[i] = 1;  //1是所有数的真因数所以全部置1   
  21.       
  22.     for  (i = 2; i + i <= 5000000; i++)   //预处理,预处理是logN(调和级数)*N。   
  23.         //@litaoye:调和级数1/2 + 1/3 + 1/4......的和近似为ln(n),   
  24.         //因此O(n *(1/2 + 1/3 + 1/4......)) = O(n * ln(n)) = O(N*log(N))。   
  25.     {    
  26.         //5000000以下最大的真因数是不超过它的一半的   
  27.         j = i + i;  //因为真因数,所以不能算本身,所以从它的2倍开始   
  28.         while  (j <= 5000000)   
  29.         {    
  30.             //将所有i的倍数的位置上加i   
  31.             sum[j] += i;    
  32.             j += i;       
  33.         }  
  34.     }  
  35.       
  36.     for  (i = 220; i <= 5000000; i++)    //扫描,O(N)。   
  37.     {  
  38.         // 一次遍历,因为知道最小是220和284因此从220开始   
  39.         if  (sum[i] > i && sum[i] <= 5000000 && sum[sum[i]] == i)  
  40.         {  
  41.             //去重,不越界,满足亲和   
  42.             printf("%d %d\n" ,i,sum[i]);  
  43.         }  
  44.     }  
  45.     return  0;  
  46. }  

运行结果:

    @上善若水:

    1、可能大家理解的还不是很清晰,我们建立一个5 000 000 的数组,从1到2 500 000 开始,在每一个下标是i的倍数的位置上加上i,那么在循环结束之后,我们得到的是什么?是 类似埃斯托拉晒求素数的数组(当然里面有真的亲和数),然后只需要一次遍历就可以轻松找到所有的亲和数了。时间复杂度,线性。

    2、我们可以清晰的发现连续数据的映射可以通过数组结构本身的特点替代,用来节约空间,这是数据结构的艺术。在大规模连续数据的回溯处理上,可以通过转化为递推生成的方法,逆向思维操作,这是算法的艺术。

    3、把最简单的东西运用的最巧妙的人,要比用复杂方法解决复杂问题的人要头脑清晰。


第三节、程序的构造与解释
    我再来具体解释下上述程序的原理,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,...

本章完。

面试题征集令

  1. 十三个经典算法研究系列+附、红黑树系列(国内有史以来最为经典的红黑树教程),共计20+6=26篇文章,带目录+标签的PDF文档,耗时近一个星期,足足346页(够一本书的分量了),已在花明月暗的帮助下,正式制作完成。
  2. 想要的,发一道你自认为较好的面试题(c,c++,数据结构,算法,智力题,数字逻辑或运算题),即可。我收到后,三天之内传送此PDF文件。July、20110.5.24.此声明永久有效。
0
0
分享到:
评论

相关推荐

    算法-亲和数(信息学奥赛一本通-T1154)(包含源程序).rar

    在信息学竞赛中,亲和数问题通常被用作考察选手的算法设计、数据结构以及计算效率的能力。解这类问题时,我们需要了解以下几个关键知识点: 1. **因子和计算**:首先,要解决亲和数问题,必须掌握如何计算一个数的...

    完美数与亲和数问题对PA的条件独立性———对一些数论问题的逻辑讨论(Ⅲ) (2002年)

    自然数系N中的完美数和亲和数问题,是数论中经典的古老问题之一。完美数是指一个正整数,它等于其所有真因子之和,例如6、28和496等;而亲和数则是一对正整数,其中每一个数都是对方所有真因子之和,例如(220, 284...

    相亲数和亲和数优化源码

    相亲数和亲和数在计算机科学中是两个与数学和算法优化相关的概念,尤其是在高性能计算领域。本项目可能是一个竞赛项目,目标是通过优化代码来提高计算效率,特别是在Intel处理器上的线程调度。 相亲数(Amicable ...

    100题全.zip_matlab solve_noj亲和数_variousivw_你会存钱吗noj

    matlab solve_noj亲和数_variousivw_你会存钱吗noj”暗示了这是一个包含多个编程问题解答的压缩包,主要使用MATLAB语言,涉及到解决超越方程、亲和数的概念,以及可能与金融计算相关的问题——“你会存钱吗noj”。...

    文档博客1.docx

    ### 亲和数问题解析与C++实现 #### 一、问题定义 在数学领域,亲和数(Amicable numbers)是指两个不同的自然数,其中一个数的所有真因子(即不包括自身在内的因子)之和恰好等于另一个数,反之亦然。例如,如果...

    基于C语言实现亲和数

    一般地讲,如果两个数中任何一个数都是另一个数的真约数之和,则这两个数就是亲和数。 你的任务就编写一个程序,判断给定的两个数是否是亲和数 Input 输入数据第一行包含一个数M,接下有M行,每行一个实例,包含两...

    程序员编程艺术--共二十七章-集锦与总结(教你如何编程)

    - 数学问题(如亲和数问题) - 数据结构(如链表问题) - 排序算法(如给定大量数据的排序方法) - 算法设计(如最长公共子序列问题) #### 4. 特色与亮点 - **高质量内容**:每篇文章都经过了精心的打磨和完善...

    程序员编程艺术第一~二十七章集锦与总结(教你如何编程)(by_July)定稿版

    ##### 第六章:亲和数问题——求解500万以内的亲和数 解释了亲和数的概念,并提供了求解特定范围内所有亲和数的有效算法。 ##### 第七章:求连续子数组的最大和 这是一个经典的动态规划问题,本书提供了详细的...

    程序员编程艺术第一 ~二十七章

    - **第六章:亲和数问题--求解500万以内的亲和数** - 讨论了亲和数的定义及其求解方法。 - **第七章:求连续子数组的最大和** - 使用动态规划方法解决了最大子数组和的问题。 - **第八章:从头至尾漫谈虚函数** ...

    程序员编程艺术第一~二十七章集锦与总结

    - **第六章:亲和数问题——求解500万以内的亲和数** —— 介绍了亲和数的概念,并实现了一个高效的算法来找到指定范围内的所有亲和数。 - **第七章:求连续子数组的最大和** —— 分析了动态规划方法在解决这类问题...

    程序员编程艺术 第一~二十七章集锦与总结

    6. **亲和数问题——求解500万以内的亲和数** - **知识点**:数学问题求解、素数筛法 - **内容概述**:介绍了一种特殊类型的数学问题——亲和数的定义及其求解方法。利用素数筛法快速计算因子和,进而找出所有500...

    程序员编程艺术

    - 第六章讨论了亲和数问题,即求解500万以内的一对亲和数。 **5. 子数组最大和** - 第七章重点介绍了求解连续子数组的最大和问题。 **6. 虚函数与链表** - 第八章全面阐述了虚函数的概念和用法。 - 第九章则...

    程序员编程艺术第一~二十七章集锦与总结(教你如何编程)(by_July)定稿版.pdf

    - **第六章**:亲和数问题 - **第七章**:求连续子数组的最大和 - **第八章**:从头至尾漫谈虚函数 - **第九章**:闲话链表追赶问题 - **第十章**:如何给10^7个数据量的磁盘文件排序 - **第十一章**:最长...

    程序员编程艺术第一~三十七章集锦by_July

    - **经典问题解法**:类似strstr/strcpy/strpbrk的函数实现、亲和数问题、连续子数组的最大和。 - **数据结构**:虚函数、链表、全排列、跳台阶。 - **数据处理**:10^7个数据量的磁盘文件排序、中签概率、IP访问...

    程序员编程艺术第一~二十七章集锦与总结(教你如何编程)

    - **第六章:亲和数问题——求解500万以内的亲和数** - **知识点**:数学算法、素数筛法。 - **应用场景**:数学研究、密码学等。 - **第七章:求连续子数组的最大和** - **知识点**:动态规划算法。 - **应用...

    算法_三十七章集锦by_July

    7. 第五章到第七章涉及到了寻找和为定值的两数之和、亲和数问题以及求连续子数组的最大和等经典问题,这些问题都需要运用数学和算法知识来解决。 8. 第八章到第十章讨论了面向对象编程中的虚函数、链表问题和大数据...

    易语言设置cpu亲和性

    设置cpu 亲和性的 易语言源代码 我的cpu是 4核8线程cpu编号0-7 -2 在任务管理器设置相关性里面 就会显示6号cpu 如果减去1 那就是7号cpu NUMBER_OF_PROCESSORS 环境变量是显示你多少核心数

    Windows下动态绑定进程的CPU亲和性的实例,内附实例,可以直接运行查看结果。

    在Windows操作系统中,CPU亲和性(CPU Affinity)是一种技术,它允许操作系统或应用程序将一个...学习并理解这个实例,开发者可以更好地控制他们的应用程序在多核系统中的执行方式,从而提高效率或解决特定的性能问题。

    小学数学数学故事趣味数学亲和的友好数

    【小学数学】趣味数学中的"亲和的友好数"是一个引人入胜的概念,它在激发孩子们对数学兴趣方面起着重要作用。友好数,顾名思义,是指两个自然数之间的一种特殊关系,它们彼此友好,就像好朋友一样互相支持。这个概念...

    一类素数问题等对PA的条件独立性关---对一些数论问题的逻辑讨论(Ⅳ) (2004年)

    最后,文章提到的多重完美数和亲和数问题,是数论中较为宽泛和深入的领域。对于这些未解决的问题,文章认为它们对PA具有条件独立性,这意味着在PA体系内无法完全解决这些问题,需要额外的数学工具或原理来进一步研究...

Global site tag (gtag.js) - Google Analytics