有趣的整数"类习题、面试题详解(第一篇)

本文通过C++编程探讨了几种特殊数的查找方法,包括完数、水仙花数、亲密数、自守数及素数。提供了详细的算法实现,并对每种数的概念进行了简单解释。

1题:完数

如果一个数恰好等于其因子之和,这个数就称为完数。例如:6 = 1 + 2 + 3。编写程序,求出10000以内的所有完数。

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #define MAXN 50000  
  3. int main(void)  
  4. {  
  5.     int divisor[MAXN];              //Use to save factors  
  6.     int p = 0, count = 0, num = 0;  
  7.     int numsave = 0, divisortest = 0, i = 0;  
  8.   
  9.     for (num = 1; num < 10000; num++)  
  10.     {  
  11.         p = 0;  
  12.         numsave = num;  
  13.         for (divisortest = 1; divisortest < num / 2 + 1; divisortest++)  
  14.         {  
  15.             if (num % divisortest == 0)  
  16.             {  
  17.                 divisor[p++] = divisortest;  
  18.                 numsave -= divisortest;  
  19.             }  
  20.         }  
  21.   
  22.         if (numsave == 0)  
  23.         {  
  24.             printf("%d:%4d = ", ++count, num);  
  25.             for (i = 0; i < p - 1; i++)  
  26.             {  
  27.                 printf("%d + ", divisor[i]);  
  28.             }  
  29.             printf("%d\n", divisor[p - 1]);  
  30.         }  
  31.     }  
  32.   
  33.   return 0;  
  34. }  
解析:虽然从结果来看MAXN只需取15即可,但如果你这么做必然会导致段错误。因为num = 9720时,它需要47个数组单元来存储其因子,访问的数组过界了。


2题:水仙花数

数值等于各位数字的三次幂之和,例如:153 = 1^3 + 5^3 + 3^3,称为水仙花数。编程求出所有水仙花数。

[cpp]  view plain copy
  1. #include <stdio.h>  
  2.   
  3. int main(void)  
  4. {  
  5.     int i, j, k, num;  
  6.     for (num = 100; num < 1000; num++)  
  7.     {  
  8.         i = num / 100;  
  9.         k = num % 10;  
  10.         j = num % 100 / 10;  
  11.   
  12.         if (i * i * i + j * j * j + k * k * k == num)  
  13.             printf("%d\n", num);  
  14.     }  
  15.   
  16.     return 0;  
  17. }  

3题:亲密数

假设有a、b两个数,若a的所有因子之和等于b,b的所有因子之和等于a(因子包括1不包括自身),并且a不等于b,则称a和b是一对亲密数。例如:整数220的因子之和为284,284的因子之和为220,所以220和284是一对亲密数。请求出5000以内的亲密数。

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #define MAXN 5000  
  3.   
  4. int main(void)  
  5. {  
  6.     int i, a, b, tempa, tempb;  
  7.     int fact_a[MAXN] = {0}, pa;  
  8.     int fact_b[MAXN] = {0}, pb;  
  9.   
  10.     for (a = 1; a < 5000; a++)      //a is bigger  
  11.     {  
  12.         tempa = 0;  
  13.         tempb = 0;  
  14.         pa = 0;  
  15.         pb = 0;  
  16.         for (i = 1; i < (a / 2 + 1); i++)  
  17.         {  
  18.             if (a % i == 0)  
  19.             {  
  20.                 fact_a[pa++] = i;  
  21.                 tempa += i;  
  22.             }  
  23.         }  
  24.   
  25.         if (tempa > a)                      //to ensure b > a  
  26.         {  
  27.             for (i = 1; i < (tempa / 2 + 1); i++)  
  28.             {  
  29.                 if (tempa % i == 0)  
  30.                 {  
  31.                     fact_b[pb++] = i;  
  32.                     tempb += i;  
  33.                 }  
  34.             }  
  35.         }  
  36.   
  37.         if (tempb == a)  
  38.         {  
  39.             printf("%d AND %d:\n", a, tempa);  
  40.             printf("%d = ", a);  
  41.             for (i = 0; i < pa - 1; i++)  
  42.                 printf("%d + ", fact_a[i]);  
  43.             printf("%d\n", fact_a[i]);  
  44.   
  45.             printf("%d = ", tempa);  
  46.             for (i = 0; i < pb - 1; i++)  
  47.                 printf("%d + ", fact_b[i]);  
  48.             printf("%d\n", fact_b[i]);  
  49.         }  
  50.     }  
  51.   
  52.     return 0;  
  53. }  
解析:220与284是一对亲密数,改变顺序后284与220就不能再算做亲密数了。

4题:自守数

自守数是指一个数的平方结果的后几位数等于该数自身的这样一种自然数。例如:6的平方等于36,尾数是6,所以6是自守数。25的平方等于625,尾数是25,所以25是自守数。编程求出指定范围内的自守数。分析如下:

(1)比较自然的思路是:计算数n的平方,再截取相应位数与n比较,若相等则表示找到自守数。由于计算机变量存储范围有限,这种思路对于过大的整数没办法计算。

(2)为了计算更大的自守数,需采用以下思路。例如:625 * 625,实际只关心积的后3位。

1)对于个位数与被乘数相乘的积中,用被乘数625与乘数的个位5相乘;

2)对于十位与被乘数相乘的积中,用被乘数的后两位25与乘数的十位20相乘;

3)对于百位数与被乘数相乘的积中,用被乘数的后1位5与乘数的百位600相乘。

将以上各位相乘的积累加,再取后3位即可。

[cpp]  view plain copy
  1. #include <stdio.h>  
  2.   
  3. int main(void)  
  4. {  
  5.     int a, b, t_a;  
  6.     long n, m, tempm, sum, x , y;  
  7.     scanf("%ld", &n);  
  8.   
  9.     for (m = 1; m < n; m++)  
  10.     {  
  11.         tempm = m;  
  12.         a = 1;  
  13.         b = 10;  
  14.         sum = 0;  
  15.         while (tempm > 0)  
  16.         {  
  17.             tempm /= 10;  
  18.             a *= 10;  
  19.         }  
  20.   
  21.         t_a = a;  
  22.         while (t_a > 10)  
  23.         {  
  24.             x = m % t_a;  
  25.             y = m % b - m % (b / 10);  
  26.             sum = (sum + (x * y)) % a;  
  27.             t_a /= 10;  
  28.             b *= 10;  
  29.         }  
  30.   
  31.         if (sum == m)  
  32.             printf("%ld ", m);  
  33.     }  
  34.     printf("\n");  
  35.   
  36.     return 0;  
  37. }  

5题:素数

除了1和自身之外,没有别的因数的数。两种思路:(1)普通法;(2)Eratosthenes筛选法。

[cpp]  view plain copy
  1. //普通法  
  2. int IsPrime(int m)  
  3. {  
  4.     int i, flag = 1;  
  5.     for (i = 2; i * i < m + 1; i++)  
  6.     {  
  7.         if (m % i == 0)  
  8.         {  
  9.             flag = 0;  
  10.             break;  
  11.         }  
  12.     }  
  13.       
  14.     return flag;  
  15. }  

[cpp]  view plain copy
  1. //筛选法  
  2. #include <stdio.h>  
  3. #define MAXN 1000  
  4.   
  5. int main(void)  
  6. {  
  7.     int Prime[MAXN + 1], i, j;  
  8.     for (i = 2; i < MAXN + 1; i++)  
  9.         Prime[i] = 1;  
  10.     for (i = 2; i * i < MAXN + 1; i++)  
  11.     {  
  12.         if (Prime[i] == 1)  
  13.         {  
  14.             for (j = 2 * i; j < MAXN + 1; j++)  
  15.             {  
  16.                 if (j % i == 0)  
  17.                     Prime[j] = 0;  
  18.             }  
  19.         }  
  20.     }  
  21.   
  22.     for (i = 2; i < MAXN + 1; i++)  
  23.     {  
  24.         if (Prime[i])  
  25.             printf("%d ", i);  
  26.     }  
  27.     printf("\n");  
  28.   
  29.     return 0;  
  30. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值