习题 2-1
打印出所有的“水仙花数”,所谓“水仙花数”是指一个三位数,其各位数字立方和等于该数本身。
例如:153是一个“水仙花数”,因为153=13+53+33。
程序 2-1
#include<stdio.h> int main() { int i = 100; while (i < 1000) { int A = i /100; int B = i / 10 % 10; int C = i % 10; if (i == A * A * A + B * B * B + C * C *C) printf("%d\n", i); i++; } return 0; }
习题2-2 韩信点兵
相传韩信才智过人,从不直接清点自己军队的人数,只要让士兵先后以三人一排,五人一排,七人一排地变换队形,而他每次只掠一眼队伍的排尾就知道总人数了。输入包含多组数据,每组数据包含3个非负整数a,b,c, 表示每种队形排尾人数(a<3,b<5,c<7),输出总人数的最小值(或报告无解)。已知总人数不小于10,不超过100。输入到文件结束为止。
【分析】第一种方法直接暴力求解,最容易想到。第二种方法是我在搜索资料时发现的,顺便就学了并用代码实现了下。
程序 2-2 (a)
#include<stdio.h> int main() { int a, b, c, kase = 0; while(scanf("%d %d %d", &a, &b, &c) == 3); { for (int i = 10; i <= 100; i++) { //直接判断 i 是否满足条件 if (i % 3 == a && i % 5 == b && i % 7 == c) { printf("Case %d : %d \n", ++kase, i); break; } if (i == 100) { printf("Case %d : No answer \n", ++kase); break; } } } return 0; }
算法简单的使用了中国剩余定理。
接下来是直接贴有关知识点。
一般地有如下定义
定义 对于整数 a 、b及自然数 n ,如有
a = n q1 + r1 ,(r1 <n)
b = n q2 + r2 , (r2 <n) 并且r1= r2
则称a与b对于模n同余,记作a≡b(mod n )上式叫做同余式。
还需要下面两个定理
定理1 如a被n除所得的余数等b被n除所得的余数,c被n除所得的余数等于d被n除所得的余数, 则ac被n除所得的余数等于b d被n除所得的余数。
用同余式叙述就是:
如a≡b(mod n ),c≡d(mod n )
则ac≡b d(mod n )
定理2 被除数a加上或减去除数b的倍数,再除以b,余数r不变。即
如a ≡ r(mod b ),则a ± b n≡r(mod b )
例如70≡1(mod 3 )可得70±10×3≡1(mod 3 )
例如:一个数除以3余2,除以5余3,除以7余2,求适合条件的最小的自然数χ。
解:由题意可得同余式组
Χ≡2(mod 3 )
Χ≡3(mod 5 )
Χ≡2(mod 7)
解:[ 5,7]=35,35≡2(mod 3 ),35为5与7的倍数,且被3除余2
[ 3,7]=21,21≡1(mod 5),又3≡3(mod 5),由定理1 得,
21×3≡1×3(mod 5 ),即63≡3(mod 5 ),63为3yu7的倍数,且被5除余3
[ 3,5]=15,15≡1(mod 7),又2≡2(mod 7),由定理1 得,
15×2≡1×2(mod7 ),即30≡2(mod 7),30为3与5的倍数,且被7除余2
35+63+30=128 由定理2 知
128≡2(mod3)
128≡3(mod 5)
128≡2(mod 7)
128适合题中条件但不是最小的数
又∵[3,5, 7]=105
∴128 -105=23
由定理2 知,23仍适合条件且是最小的自然数。
※ ※ ※ ※ ※ ※ ※
例如:一个数除以5余4,除以7余2,除以11余8,求适合条件的最小的自然数χ。
解:由题意可得同余式组
Χ≡4(mod 5 )
Χ≡2(mod 7 )
Χ≡8(mod 11)
[ 7,11]=77,77≡2(mod 5 )又2≡2(mod 5 ),由定理1 得,
77×2≡2×2(mod 5 ),即154≡4(mod 5 )
154为7与11的倍数,且被5除余4
[ 5,11]=55,55≡6(mod 7 ),又5≡5(mod 7 ),由定理1 得,
55×5≡6×5(mod 7),275≡30(mod 7),
275为5与11的倍数,且被7除余2
[ 5,7]=35,35≡2(mod 11 ),又4≡2(mod 11 ),由定理1 得,
35×4≡2×4(mod 11 ),即140≡8(mod 11 )
140为5与7的倍数,且被11除余8
154+275+140=569 由定理2 知
569≡4(mod 5 )
569≡2(mod 7 )
569≡8(mod 11)
569适合题中条件但不是最小的数
又∵[5, 7,11]=385
∴569 -385=184
代码实现如下:
程序 2-2 (b)
#include<stdio.h> int main() { //分别找出能被两个数整除,而满足被第三个整除余一的最小的数 int a, b, c, total, kase = 0; while (scanf("%d%d%d",&a, &b, &c) == 3) { int A = 0, B = 0, C = 0; //首先要满足能被两个数整除 A = 5 * 7; //然后要满足能被第三个数除余且值为相对应的a,b,c //若不满足,根据定理一进行相乘处理 if (A % 3 != a) { A = A * a; } B = 3 * 7; if (B % 5 != b) { B = B *b; } C = 3 * 5; if (C % 7 != c) { C = C * c; } //得出一个初步值 total = A + B + C; //初步值不一定是满足条件的最小值,若比公倍数大则要减去公倍数 if (total > 105) { total -= 105; } //最后进行验算,并判断是不是在条件区间内 if (total % 3 == a && total % 5 == b && total % 7 == c && total > 10 && total < 100) { printf("Case %d : %d\n", ++kase, total); } else { printf("Case %d : No answer", ++kase); } } return 0; }
习题 2-3 输入正整数 n <= 20, 输出一个n层的倒三角形。
没难度直接上代码
程序 2-3
#include<stdio.h> int main() { int n = 0; scanf("%d", &n); for (int i = 1; i <= n; i++) { int space = i -1; for (int j = 0; j < space; j++) printf(" "); int jinhao = 2 * n - 2 * i +1; for (int k = 0; k < jinhao; k++) printf("#"); printf("\n"); } }
习题 2-4子序列求和
输入两个正整数, n < m < 106, 输出1 / n2 + 1 / (n + 1)2 + …… + 1 / m2 ,保留5位小数。输入包含多组数据,结束标记为 n = m = 0。
样例输入:
2 4
65536 655360
0 0
样例输出:
Case 1 : 0.42361
Case 2 : 0.00001
程序 2-4
#include<stdio.h> int main() { int n, m; int kase = 0; double sum= 0; while(scanf("%d %d", &n, &m) == 2 && n) { sum = 0; for (int i =n; i <= m; i++) { long temp = i * i;; sum += 1.0 / temp; } printf("Case %d : %.6f\n", ++kase, sum); } }
本题有陷阱,数字太大乘法会溢出,观察发现1 / 100002对结果影响很小了,可以考虑定一个界限,再大的值定为0;
习题 2-5 分数化小数
输入正整数a,b,c, 输出 a/b的小数形式,精确到小数点 c 位。 a,b <= 10, c <= 100。输入包含多组数据,结束标记为 a = b = c = 0;
样例输入:
1 6 4
0 0 0
程序 2-5
#include<stdio.h> int main() { int a, b, c, kase = 0; while(scanf("%d%d%d", &a, &b, &c) == 3 && a) { double decimal = a * 1.0 / b; //注意通配符 * 号和取代 * 号的 c 的顺序 printf("Case %d : %.*f\n", ++kase, c, decimal); } return 0; }
习题2-6 排列
用1, 2, 3 ……9组成的3个三位数字 abc,def,ghi,每个数字恰好使用一次,要求 abc:def:ghi = 1:2:3。按照“abc def ghi ”的格式输出所有解,每行一个解。
【分析】有两个难点。
1.每个数字只用一次。
2.abc:def:ghi = 1:2:3
程序2-6
#include<stdio.h> int main() { //只需给出 abc 就可以通过 *2, *3得到def,ghi //abc 最小为 123 int abc = 123; //abc最大值为329,应为 abc*3最大为987 for (abc; abc <= 329; abc++) { int a,b,c,def,d,e,f,ghi,g,h,i,sum,mul; a = abc / 100; b = abc / 10 % 10; c = abc % 10; def = abc * 2; d = def / 100; e = def / 10 % 10; f = def % 10; ghi = abc * 3; g = ghi / 100; h = ghi / 10 % 10; i = ghi % 10; //将每个数的每位值分别相加,相乘 sum = a + b + c + d + e + f + g + h +i; mul = a *b * c * d * e * f * g * h * i; //因为每个数字只用一次,所以他们的和始终为 45 ,积始终为 362880 if (sum == 45 && mul == 362880) printf("%d %d %d\n", abc, def, ghi); } return 0; }