C/C++语言经典、实用、趣味程序设计编程百例精解(3)
21.位反序数
设N是一个四位数,它的9倍恰好是其反序数,求N。反序数就是将整数的数字倒过来形成的整数。例如:1234的反序数是4321。
*问题分析与算法设计
可设整数N的千、百、十、个位为i、j、k、l,其取值均为0~9,则满足关系式:
(i*103+j*102+10*k+l)*9=(l*103+k*102+10*j+i)
的i、j、k、l即构成N。
*程序说明与注释
1. #include<stdio.h> 2. int main() 3. { 4. int i; 5. for(i=1002;i<1111;i++) /*穷举四位数可能的值*/ 6. if(i%10*1000+i/10%10*100+i/100%10*10+i/1000==i*9)/*判断反序数是否是原整数的9倍*/ 7. printf("The number satisfied stats condition is: %d\n",i);/*若是则输出*/ 8. return 0; 9. }
*运行结果
The number satisfied states condition is:1089
22.求车速
一辆以固定速度行驶的汽车,司机在上午10点看到里程表上的读数是一个对称数(即这个数从左向右读和从右向左读是完全一样的),为95859。两小时后里程表上出现了一个新的对称数。问该车的速度是多少?新的对称数是多少?
*问题分析与算法设计
根据题意,设所求对称数为i,其初值为95589,对其依次递增取值,将i值的每一位分解后与其对称位置上的数进行比较,若每个对称位置上的数皆相等,则可判定i即为所求的对称数。
*程序说明与注释
1. #include<stdio.h> 2. int main() 3. { 4. int t,a[5]; /*数组a存放分解的数字位*/ 5. long int k,i; 6. for(i=95860;;i++) /*以95860为初值,循环试探*/ 7. { 8. for(t=0,k=100000;k>=10;t++) /*从高到低分解所取i值的每位数*/ 9. { /* 字,依次存放于a[0]~a[5]中*/ 10. a[t]=(i%k)/(k/10); 11. k/=10; 12. } 13. if((a[0]==a[4])&&(a[1]==a[3])) 14. { 15. printf("The new symmetrical number kelometers is:%d%d%d%d%d\n",a[0],a[1],a[2],a[3],a[4]); 16. printf("The velocity of the car is: %.2f\n",(i-95859)/2.0); 17. break; 18. } 19. } 20. return 0; 21. }
*运行结果
The new symmetrical number kelometers is:95959.
The velocity of the car is:50.00
*思考题
将一个数的数码倒过来所得到的新数叫原数的反序数。如果一个数等于它的反序数,则称它为对称数。求不超过1993的最大的二进制的对称数。
23.由两个平方三位数获得三个平方二位数
已知两个平方三位数abc和xyz,其中a、b、c、x、y、z未必是不同的;而ax、by、cz是三个平方二位数。请编程求三位数abc和xyz。
*问题分析与算法设计
任取两个平方三位数n和n1,将n从高向低分解为a、b、c,将n1从高到低分解为x、y、z。判断ax、by、cz是否均为完全平方数。
*程序说明与注释
1. #include<stdio.h> 2. #include<math.h> 3. void f(int n,float* s); 4. int main() 5. { 6. int i,t; 7. float a[3],b[3]; 8. printf("The possible perfect squares combinations are:\n"); 9. for(i=11;i<=31;++i) //穷举平方三位数的取值范围 10. for(t=11;t<=31;++t){ 11. f(i*i,a); //分解平方三位数的各位,每位数字分别存入数组中 12. f(t*t,b); 13. if(sqrt(a[0]*10+b[0]) == (int)sqrt(a[0]*10+b[0]) && 14. sqrt(a[1]*10+b[1]) == (int)sqrt(a[1]*10+b[1])&& 15. sqrt(a[2]*10+b[2]) == (int)sqrt(a[2]*10+b[2]) ) 16. { 17. printf("%d and %d\n",i*i,t*t); //若三个新的数均是完全平方数,则输出 18. } 19. } 20. } 21. /* 分解三位数n的各位数字,将各个数字从高到低依次存入指针s所指向的数组中*/ 22. void f(int n,float* s){ 23. int k; 24. for(k=1000;k>=10;++s){ 25. *s = (n%k) /(k/10);k /=10; 26. } 27. }
*运行结果
The possible perfect squares combinations are:
400 and 900
841 and 196
*思考题
求这样一个三位数,该三位数等于其每位数字的阶乘之和。
即 abc = a! + b! + c!
(正确结果:145 = 1! + 4! +5!)
24.阿姆斯特朗数
如果一个正整数等于其各个数字的立方和,则称该数为阿姆斯特朗数(亦称为自恋性数)。
如 407=43+03+73就是一个阿姆斯特朗数。试编程求1000以内的所有阿姆斯特朗数。
*问题分析与算法设计
可采用穷举法,依次取1000以内的各数(设为i),将i的各位数字分解后,据阿姆斯特朗数的性质进行计算和判断。
*程序说明与注释
1. #include<stdio.h> 2. int main() 3. { 4. int i,t,k,a[3]; 5. printf("There are follwing Armstrong number smaller than 1000:\n"); 6. for(i=2;i<1000;i++) /*穷举要判定的数i的取值范围2~1000*/ 7. { 8. for(t=0,k=1000;k>=10;t++) /*截取整数i的各位(从高向低位)*/ 9. { 10. a[t]=(i%k)/(k/10); /*分别赋于a[0]~a[2}*/ 11. k/=10; 12. } 13. if(a[0]*a[0]*a[0]+a[1]*a[1]*a[1]+a[2]*a[2]*a[2]==i)/*判断i是否为阿姆斯特朗数*/ 14. printf("%5d",i); /*若满足条件,则输出*/ 15. } 16. printf("\n"); 17. }
*运行结果
There are following Armstrong number smaller than 1000:
153 370 371 407
25.完全数
如果一个数恰好等于它的因子之和,则称该数为“完全数”。
*问题分析与算法设计
根据完全数的定义,先计算所选取的整数a(a的取值1~1000)的因子,将各因子累加于m,若m等于a,则可确认a为完全数。
*程序说明与注释
1. #include<stdio.h> 2. int main() 3. { 4. int a,i,m; 5. printf("There are following perfect numbers smaller than 1000:\n"); 6. for(a=1;a<1000;a++) /*循环控制选取1~1000中的各数进行判断*/ 7. { 8. for(m=0,i=1;i<=a/2;i++) /*计算a的因子,并将各因子之和m=a,则a是完全数输出*/ 9. if(!(a%i)) m+=i; 10. if(m==a) 11. printf("%4d ",a); 12. } 13. printf("\n"); 14. }
*运行结果
TThere are following perfect numbers smaller than 1000:
6 28 496
26.亲密数
如果整数A的全部因子(包括1,不包括A本身)之和等于B;且整数B的全部因子(包括1,不包括B本身)之和等于A,则将整数A和B称为亲密数。求3000以内的全部亲密数。
*问题分析与算法设计
按照亲密数定义,要判断数a是否有亲密数,只要计算出a的全部因子的累加和为b,再计算b的全部因子的累加和为n,若n等于a则可判定a和b是亲密数。计算数a的各因子的算法:
用a依次对i(i=1~a/2)进行模运算,若模运算结果等于0,则i为a的一个因子;否则i就不是a的因子。
*程序说明与注释
1. #include<stdio.h> 2. int main() 3. { 4. int a,i,b,n; 5. printf("There are following friendly–numbers pair smaller than 3000:\n"); 6. for(a=1;a<3000;a++) /*穷举1000以内的全部整数*/ 7. { 8. for(b=0,i=1;i<=a/2;i++) /*计算数a的各因子,各因子之和存放于b*/ 9. if(!(a%i))b+=i; /*计算b的各因子,各因子之和存于n*/ 10. for(n=0,i=1;i<=b/2;i++) 11. if(!(b%i))n+=i; 12. if(n==a&&a<b) 13. printf("%4d..%4d ",a,b); /*若n=a,则a和b是一对亲密数,输出*/ 14. } 15. }
*运行结果
There are following friendly–numbers pair smaller than 3000:
220.. 284 1184.. 1210 2620.. 2924
27.自守数
自守数是指一个数的平方的尾数等于该数自身的自然数。例如:
252=625 762=5776 93762=87909376
请求出200000以内的自守数
*问题分析与算法设计
若采用“求出一个数的平方后再截取最后相应位数”的方法显然是不可取的,因为计算机无法表示过大的整数。
分析手工方式下整数平方(乘法)的计算过程,以376为例:
376 被乘数
X 376 乘数
———
2256 第一个部分积=被乘数*乘数的倒数第一位
2632 第二个部分积=被乘数*乘数的倒数第二位
1128 第三个部分积=被乘数*乘数的倒数第三位
———
141376 积
本问题所关心的是积的最后三位。分析产生积的后三位的过程,可以看出,在每一次的部分积中,并不是它的每一位都会对积的后三位产生影响。总结规律可以得到:在三位数乘法中,对积的后三位产生影响的部分积分别为:
第一个部分积中:被乘数最后三位*乘数的倒数第一位
第二个部分积中:被乘数最后二位*乘数的倒数第二位
第三个部分积中:被乘数最后一位*乘数的倒数第三位
将以上的部分积的后三位求和后截取后三位就是三位数乘积的后三位。这样的规律可以推广到同样问题的不同位数乘积。
按照手工计算的过程可以设计算法编写程序。
*程序说明与注释
1. #include<stdio.h> 2. int main() 3. { 4. long mul,number,k,ll,kk; 5. printf("It exists following automorphic nmbers small than 200000:\n"); 6. for(number=0;number<200000;number++){ 7. /*由number的位数确定截取数字进行乘法时的系数k*/ 8. for(mul=number,k=1;(mul/=10)>0;k*=10); 9. kk=k*10; /*kk为截取部分积时的系数*/ 10. mul=0; /*积的最后n位*/ 11. ll=10; /*ll为截取乘数相应位时的系数*/ 12. while(k>0){ 13. mul=(mul+(number%(k*10))*(number%ll-number%(ll/10)))%kk; 14. /*(部分积+截取被乘数的后N位*截取乘数的第M位),%kk再截取部分积*/ 15. k/=10; /*k为截取被乘数时的系数*/ll*=10; 16. } 17. if(number==mul) /*判断若为自守数则输出*/ 18. printf("%ld ",number); 19. } 20. }
*运行结果
It exsts following automorphic numbners smaller than 200000:
0 1 5 6 25 76 376 625 9376 90625 109376
28.回文数
打印所有不超过n(取n<256) 的其平方具有对称性质的数(也称回文数)。
*问题分析与算法设计
对于要判断的数n,计算出其平方后(存于a),将a的每一位进行分解,再按a的从低到高的顺序将其恢复成一个数k(如n=13,则a=169且k=961),若a等于k则可判定n为回亠数。
*程序说明与注释
1. #include<stdio.h> 2. void GetDigit(int number, int(&arr)[16], int& length){ 3. for (length = 0; number != 0; ++length) /*从低到高分解数a的每一位存于数组m[0]~m[16]*/ 4. { 5. arr[length] = number % 10;//这个是取得a的个位,整个循环合起来就可以取得各个位 6. number /= 10; 7. } 8. } 9. bool IsCircle(int(&arr)[16], int length){ 10. //因为n的平方的各个位都存在数组中了,下面判断是不是对称 11. for (int i = 0, j = length-1; i <= j; ++i, --j) 12. { 13. if (arr[j] != arr[i]) 14. return false;//只要有一位不是对称,那就说明不是对称,就可以退出了 15. } 16. return true; 17. } 18. int main(void){ 19. int digitArray[16] = {0}; 20. printf("No. number it's square(palindrome)\n"); 21. for (int n = 1; n < 1000; n++) /*穷举n的取值范围*/ 22. { 23. auto a = n * n; /*计算n的平方*/ 24. int length = 0; 25. GetDigit(a, digitArray, length); 26. if (IsCircle(digitArray, length))printf("%10d %10d\n", n, a); 27. } 28. return 0; 29. }
*运行结果
No. number it's square(palindrome)
1 1
2 4
3 9
11 121
22 484
26 676
101 10201
111 12321
121 14641
202 40804
212 44944
264 69696
307 94249
836 698896
29.求具有abcd=(ab+cd)2性质的四位数
3025这个数具有一种独特的性质:将它平分为二段,即30和25,使之相加后求平方,即(30+25)2,恰好等于3025本身。请求出具有这样性质的全部四位数。
*问题分析与算法设计
具有这种性质的四位数没有分布规律,可以采用穷举法,对所有四位数进行判断,从而筛选出符合这种性质的四位数。具体算法实现,可任取一个四位数,将其截为两部分,前两位为a,后两位为b,然后套用公式计算并判断。
*程序说明与注释
1. #include<stdio.h> 2. int main() 3. { 4. int n,a,b; 5. printf("There are following number with 4 digits satisfied condition\n"); 6. for(n=1000;n<10000;n++) /*四位数N的取值范围1000~9999*/ 7. { 8. a=n/100; /*截取N的前两位数存于a*/ 9. b=n%100; /*截取N的后两位存于b*/ 10. if((a+b)*(a+b)==n) /*判断N是否为符合题目所规定的性质的四位数*/ 11. printf("%d ",n); 12. } 13. }
*运行结果
There are following numbers with 4 digits satisfied condition:
2025 3025 9801
30.求素数
求素数表中1~1000之间的所有素数
*问题分析与算法设计
素数就是仅能被1和它自身整除的整数。判定一个整数n是否为素数就是要判定整数n能否被除1和它自身之外的任意整数整除,若都不能整除,则n为素数。
程序设计时i可以从2开始,到该整数n的1/2为止,用i依次去除需要判定的整数,只要存在可以整除该数的情况,即可确定要判断的整数不是素数,否则是素数。
*程序说明与注释
1. #include<stdio.h> 2. int main() 3. { 4. int n1,nm,i,j,flag,count=0; 5. do{ 6. printf("Input START and END=?"); 7. scanf("%d%d",&n1,&nm); /*输入求素数的范围*/ 8. }while(!(n1>0&&n1<nm)); /*输入正确的范围*/ 9. printf("…………PRIME TABLE(%d–%d) …………\n",n1,nm); 10. if(n1==1||n1==2) /*处理素数2*/ 11. { 12. printf("%4d",2); 13. n1=3;count++; 14. } 15. for(i=n1;i<=nm;i++) /*判定指定范围内的整数是否为素数*/ 16. { 17. if(!(i%2))continue; 18. for(flag=1,j=3;flag&&j<i/2;j+=2) 19. /*判定能否被从3到整数的一半中的某一数所整除*/ 20. if(!(i%j))flag=0; /*若能整除则不是素数*/ 21. if(flag) printf(++count%15?"%4d":"%4d\n",i); 22. } 23. }
*思考题
请找出十个最小的连续自然数,它们个个都是合数(非素数)