说明如果有一数n,其真因数(Proper factor)的总和等于n,则称之为完美数(Perfect Number),例如以下几个数都是完美数:

6 = 1 + 2 + 3

28 = 1 + 2 + 4 + 7 + 14

496 = 1 + 2 + 4 + 8 + 16 + 31 + 62 + 124 + 248

 

程式基本上不难,第一眼看到时会想到使用回圈求出所有真因数,再进一步求因数和,不过若n值很大,则此法会花费许多时间在回圈测试上,十分没有效率,例如求小于10000的所有完美数。

解法如何求小于10000的所有完美数?并将程式写的有效率?基本上有三个步骤:

求出一定数目的质数表

利用质数表求指定数的因式分解

利用因式分解求所有真因数和,并检查是否为完美数

 

步骤一步骤二 在之前讨论过了,问题在步骤三,如何求真因数和?方法很简单,要先知道将所有真因数和加上该数本身,会等于该数的两倍,例如:

2 * 28 = 1 + 2 + 4 + 7 + 14 + 28

 

等式后面可以化为:

2 * 28 = (20 + 21 + 22) * (70 + 71)

 

所以只要求出因式分解,就可以利用回圈求得等式后面的值,将该值除以2就是真因数和了;等式后面第一眼看时可能想到使用等比级数公式来解,不过会使用到次方运算,可以在回圈走访因式分解阵列时,同时计算出等式后面的值,这在下面的实作中可以看到。

 

 
  
  1. #include <stdio.h>   
  2.  
  3. #include <stdlib.h>   
  4.  
  5.  
  6. #define N 1000   
  7.  
  8. #define P 10000   
  9.  
  10.  
  11. int prime(int*); // 求质数表   
  12.  
  13. int factor(int*, int, int*); // 求factor   
  14.  
  15. int fsum(int*, int); // sum ot proper factor   
  16.  
  17.  
  18. int main(void) {   
  19.  
  20. int ptable[N+1] = {0}; // 储存质数表   
  21.  
  22. int fact[N+1] = {0}; // 储存因式分解结果   
  23.  
  24. int count1, count2, i;   
  25.  
  26.  
  27. count1 = prime(ptable);   
  28.  
  29.  
  30. for(i = 0; i <= P; i++) {   
  31.  
  32. count2 = factor(ptable, i, fact);   
  33.  
  34. if(i == fsum(fact, count2))   
  35.  
  36. printf("Perfect Number: %d\n", i);   
  37.  
  38. }   
  39.  
  40.  
  41. printf("\n");   
  42.  
  43.  
  44. return 0;   
  45.  
  46. }   
  47.  
  48.  
  49. int prime(int* pNum) {   
  50.  
  51. int i, j;   
  52.  
  53. int prime[N+1];   
  54.  
  55.  
  56. for(i = 2; i <= N; i++)   
  57.  
  58. prime[i] = 1;   
  59.  
  60.  
  61. for(i = 2; i*i <= N; i++) {   
  62.  
  63. if(prime[i] == 1) {   
  64.  
  65. for(j = 2*i; j <= N; j++) {   
  66.  
  67. if(j % i == 0)   
  68.  
  69. prime[j] = 0;   
  70.  
  71. }   
  72.  
  73. }   
  74.  
  75. }   
  76.  
  77.  
  78. for(i = 2j = 0; i < N; i++) {   
  79.  
  80. if(prime[i] == 1)   
  81.  
  82. pNum[j++] = i;   
  83.  
  84. }   
  85.  
  86.  
  87. return j;   
  88.  
  89. }   
  90.  
  91.  
  92. int factor(int* table, int num, int* frecord) {   
  93.  
  94. int i, k;   
  95.  
  96.  
  97. for(i = 0k = 0; table[i] * table[i] <= num;) {   
  98.  
  99. if(num % table[i] == 0) {   
  100.  
  101. frecord[k] = table[i];   
  102.  
  103. k++;   
  104.  
  105. num /= table[i];   
  106.  
  107. }   
  108.  
  109. else   
  110.  
  111. i++;   
  112.  
  113. }   
  114.  
  115.  
  116. frecord[k] = num;   
  117.  
  118.  
  119. return k+1;   
  120.  
  121. }   
  122.  
  123.  
  124. int fsum(int* farr, int c) {   
  125.  
  126. int i, r, s, q;   
  127.  
  128.  
  129. i = 0;   
  130.  
  131. r = 1;   
  132.  
  133. s = 1;   
  134.  
  135. q = 1;   
  136.  
  137.  
  138. while(i < c) {   
  139.  
  140. do {   
  141.  
  142. r *= farr[i];   
  143.  
  144. q += r;   
  145.  
  146. i++;   
  147.  
  148. } while(i < c-1 && farr[i-1] == farr[i]);   
  149.  
  150. s *= q;   
  151.  
  152. r = 1;   
  153.  
  154. q = 1;   
  155.  
  156. }   
  157.  
  158.  
  159. return s / 2;   
  160.  
  161. }