找出給定 n 以內所有完數:真因子(不含自身)之和等於自身的數。如 6 = 1+2+3,28 = 1+2+4+7+14。核心考點:因子枚舉優化、因子配對性質、已知完數數學結構。
#include <stdio.h>
int main() {
int i, j, n, sum, k = 0, perfect[1000];
printf("請輸入整數: ");
scanf("%d", &n);
for (i = 1; i <= n; i++) {
sum = 0;
for (j = 1; j < i; j++) { // ❌ 優化至 √i
if (i % j == 0) sum += j;
}
if (sum == i) perfect[k++] = i;
}
// 輸出...
}
因子成對出現:若 j 是因子,則 i/j 也是因子。枚舉至 √i 即可獲取所有因子對。
int sum_proper_divisors(int n) {
if (n <= 1) return 0;
int sum = 1; // 1 永遠是真因子 (n>1)
for (int j = 2; j * j <= n; j++) {
if (n % j == 0) {
sum += j;
int paired = n / j;
if (paired != j) sum += paired; // 避免平方數重複加
}
}
return sum;
}
定理:所有偶數完數形式為 2^(p-1) × (2^p - 1),其中 2^p - 1 是梅森素數。
截至目前未發現奇完數(若存在則 > 10¹⁵⁰⁰)。
已知前幾個完數對應梅森素數指數 p:
| p | 梅森素數 2^p-1 | 完數 | 位數 |
|---|---|---|---|
| 2 | 3 | 6 | 1 |
| 3 | 7 | 28 | 2 |
| 5 | 31 | 496 | 3 |
| 7 | 127 | 8,128 | 4 |
| 13 | 8191 | 33,550,336 | 8 |
| 17 | 131071 | 8,589,869,056 | 10 |
| 19 | 524287 | 137,438,691,328 | 12 |
| 方法 | n=10⁶ 操作數 | 時間複雜度 | 適用場景 |
|---|---|---|---|
| 暴力 j | ~5×10¹¹ | O(n²) | 教學演示 |
| √i 配對枚舉 | ~10⁹ | O(n√n) | 通用因子和計算 |
| 篩法預計算因子和 | ~10⁷ | O(n log n) | 批量查詢 |
| 歐拉定理直接生成 | 8 次比較 | O(1) | 完數專用最優 |
void sieve_divisor_sum(int n, int *sum) {
for (int i = 1; i <= n; i++) sum[i] = 1; // 1 是所有數>1的因子
sum[1] = 0; // 1 無真因子
for (int i = 2; i <= n; i++) {
for (int j = i*2; j <= n; j += i) {
sum[j] += i; // i 是 j 的真因子
}
}
}
// 使用後 sum[i] 即為 i 的真因子和,O(n log n) 一次性算完所有
完數查找展示了從暴力枚舉到數學結構利用的算法昇華。關鍵收穫:
2^(p-1)(2^p-1),2^p-1 為梅森素數;