你也能够上程序咖(https://meta.chengxuka.com),关上大学幕题板块,岂但有答案,解说,还能够在线答题。
题目1:请画出例 5.6 中给出的3个程序段的流程图。
解∶上面别离是教材第5章例5.6给出的程序,据此画出流程图。
(1)程序1:
#include <stdio.h>int main(){ int i, j, n = 0; for (i = 1; i <= 4; i++) // n用来累计输入数据的个数 for (j = 1; j <= 5; j++, n++) { if (n % 5 == 0) printf("\n"); //管制在输入5个数据后换行 printf("%d\t", i * j); } printf("\n"); return 0;}
运行后果:
其对应的流程图见图5. 1。
(2)程序2:
#include <stdio.h>int main(){ int i, j, n = 0; for (i = 1; i <= 4; i++) for (j = 1; j <= 5; j++, n++) { if (n % 5 == 0) printf("\n"); //管制在输入5个数据后换行 if (i == 3 && j == 1) break; //遇到第3行第1列,完结内循环 printf("%d\t", i * j); } printf("\n"); return 0;}
运行后果:
遇到第3行第1列时,执行 break,完结内循环,进行第 4 次外循环。
其对应的流程图见图 5.2 。
(3)程序 3:
#include <stdio.h>int main(){ int i, j, n = 0; for (i = 1; i <= 4; i++) for (j = 1; j <= 5; j++, n++) { if (n % 5 == 0) printf("\n"); //管制在输入5个数据后换行 if (i == 3 && j == 1) continue; //遇到第3行第1列,终止本次内循环 printf("%d\t", i * j); } printf("\n"); return 0;}
运行后果:
遇到第3行第1列时,执行continue,只是提前结束本次内循环,不输入原来的第3行第1列的数3,而进行下一次内循环,接着在该地位上输入原来的第 3行第 2列的数6。
请认真辨别 break 语句和 continue 语句。
其对应的流程图见图 5.3。
题目2:请补充例 5.7 程序,别离统计当" fabs(t)>=1e-6"和"fabs(t)>=1e-8" 时执行循环体的次数。
解:
例5.7 程序是用
$$\frac{\pi}{4}\approx 1-\frac{1}{3}+\frac{1}{5}-\frac{1}{7}+...$$
公式求 的近似值,直到发现某一项的绝对值小于 10-6 为止。依据本题要求,别离统计当 fabs(t)>=1e-6 和 fabs(t)>=1e-8 时,执行循环体的次数。
(1)采纳fabs(t)>=le-6作为循环终止条件的程序补充批改如下∶
#include <stdio.h>#include <math.h> //程序中用到数学函数 fabs,应蕴含头文件math.hint main(){ int sign = 1, count = 0; // sign 用来示意数值的符号,count 用来累计循环次数 double pi = 0.0, n = 1.0, term = 1.0; // pi开始代表多项式的值,最初代表的值,,n代表分母, // term 代表以后项的值 while (fabs(term) >= 1e-6) //查看以后项 term 的绝对值是否大于或等于10的(-6)次方 { pi = pi + term; //把以后项 term 累加到 pi中 n = n + 2; // n+2是下一项的分母 sign = -sign; // sign代表符号,下一项的符号与上一项符号相同 term = sign / n; //求出下一项的值 term count++; // count 累加1 } pi = pi * 4; //多项式的和pi乘以4,才是的近似值 printf("pi=%10.8f\n", pi); //输入的近似值 printf("count=%d\n", count); //输入count的值 return 0;}
运行后果:
执行50万次循环。
(2) 采纳fabs(t)>= 1e-8作为循环终止条件的程序,只需把下面程序的第8行如下批改即可:
while (fabs(term) >= 1e-8)
运行后果:
执行5000万次循环。
题目3:输出两个正整数 m 和 n,求其最大公约数和最小公倍数。
解:
答案代码:
#include <stdio.h>int main(){ int p, r, n, m, temp; printf("请输出两个正整数n.m∶"); scanf("%d,%d,", &n, &m); if (n < m) { temp = n; n = m; m = temp; } p = n * m; while (m != 0) { r = n % m; n = m; m = r; } printf("它们的最大公约数为∶%d\n", n); printf("它们的最小公倍数为∶%d\n", p / n); return 0;}
运行后果:
题目4:输出一行字符,别离统计出其中英文字母、空格、数字和其余字符的个数。
解:
答案代码:
#include <stdio.h>int main(){ char c; int letters = 0, space = 0, digit = 0, other = 0; printf("请输人一行字符:\n"); while ((c = getchar()) != '\n') if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') letters++; else if (c == ' ') space++; else if (c >= '0' && c <= '9') digit++; else other++; printf("字母数:%d\n空格数:%d\n数字数:%d\n其余字符数:%d\n", letters, space, digit, other); return 0;}
运行后果:
题目5:求 $ S_n=a+aa+aaa+\dots+\overbrace{aa\dots a}^{\text{n个a}} $ 之值,其中a是一个数字,n示意a的位数,n由键盘输入。例如:2+22+222+2222+22222 (此时 n=5)
解:
答案代码:
#include <stdio.h>int main(){ int a, n, i = 1, sn = 0, tn = 0; printf("a,n=:"); scanf("%d, %d", &a, &n); while (i <= n) { tn = tn + a; //赋值后的tn为i个a组成数的值 sn = sn + tn; //赋值后的 sn为多项式前i项之和 a = a * 10; ++i; } printf("a十aa十aa十...=%d\n", sn); return 0;}
运行后果:
题目6:求 $ \sum_{n=1}^{20}{n!} $ (即求1!+2!+3!+4!+…+20!)。
解:
答案代码:
#include <stdio.h>int main(){ double s = 0, t = 1; int n; for (n = 1; n <= 20; n++) { t = t * n; s = s + t; } printf("1!+2!+...+20!=%22.15e\n", s); return 0;}
运行后果:
请留神:s 不应定义为 int 型或 long 型,因为在用 Turbo C 或 Turbo C++ 等编译系统时,int 型数据在内存占 2个字节,整数的范畴为-32768~32767,long 数据在内存占 4 个字节,整数的范畴为 -21亿~21亿。用Visual C++ 6.0 时,int 型和 long 型数据在内存都占4 个字节,数据的范畴为-21亿~21 亿。无奈包容求得的后果。今将 s 定义为 double 型,以失去更多的精度。在输入时,用 22.15e 格局,使数据宽度为 22,数字局部中小数位数为15位。
题目7:求 $ \sum_{k=1}^{100}k+\sum_{k=1}^{50}k^2+\sum_{k=1}^{10}\frac{1}{k} $ 。
解:
答案代码:
#include <stdio.h>int main(){ int nl = 100, n2 = 50, n3 = 10; double k, s1 = 0, s2 = 0, s3 = 0; for (k = 1; k <= nl; k++) //计算1~100的和 { s1 = s1 + k; } for (k = 1; k <= n2; k++) //计算1~50各数的平方和 { s2 = s2 + k * k; } for (k = 1; k <= n3; k++) //计算 1~10 的各倒数和 { s3 = s3 + 1 / k; } printf("sum=%15.6f\n", s1 + s2 + s3); return 0;}
运行后果∶
题目8:输入所有的"水仙花数",所谓"水仙花数"是指—个 3位数,其各位数字立方和等于该数自身。例如,153是水仙花数,因为 $ 153=1^3+5^3+3^3 $ 。
解:
答案代码:
#include <stdio.h>int main(){ int i, j, k, n; printf("parcissus numbers are "); for (n = 100; n < 1000; n++) { i = n / 100; j = n / 10 - i * 10; k = n % 10; if (n == i * i * i + j * j * j + k * k * k) printf("%d ", n); } printf("\n"); return 0;}
运行后果:
题目9:一个数如果恰好等于它的因子之和,这个数就称为"完数"。例如,6的因子为1,2,3,而 6=1+2+3 ,因而 6 是"完数"。编程序找出 1000 之内的所有完数,并按上面格局输入其因子:
6 its factors are 1,2,3
解:办法一。
答案代码:
#include <stdio.h>#define M 1000 //定义寻找范畴int main(){ int k1, k2, k3, k4, k5, k6, k7, k8, k9, k10; int i, a, n, s; for (a = 2; a <= M; a++) // a是2~1000的整数,查看它是否完数 { n = 0; // n 用来累计 a的因子的个数 s = a; // s用来寄存尚未求出的因子之和,开始时等于a for (i = 1; i < a; i++) //查看i是否 a的因子 if (a % i == 0) //如果i是 a的因子 { n++; // n加1,示意新找到一个因子 s = s - i; // s减去已找到的因子,s的新值是尚未求出的因子之和 switch (n) //将找到的因子赋给k1~k9,或 k10 { case 1: k1 = i; //找出的第1个因子赋给 k1 break; case 2: k2 = i; //找出的第2个因子赋给 k2 break; case 3: k3 = i; //找出的第3个因子赋给 k3 break; case 4: k4 = i; //找出的第 4个因子赋给k4 break; case 5: k5 = i; //找出的第5个因子赋给 k5 break; case 6: k6 = i; //找出的第6个因子赋给 k6 break; case 7: k7 = i; //找出的第7个因子赋给 k7 break; case 8: k8 = i; //找出的第 8个因子赋给 k8 break; case 9: k9 = i; //找出的第9个因子赋给 k9 break; case 10: k10 = i; //找出的第 10个因子赋给k10 break; } } if (s == 0) { printf("%d ,Its factors are", a); if (n > 1) printf("%d,%d", k1, k2); // n > 1示意a至多有2个因子 if (n > 2) printf(",%d", k3); // n>2示意至多有3个因子,故应再输入一个因子 if (n > 3) printf(",%d", k4); // n>3示意至多有4个因子,故应再输入一个因子 if (n > 4) printf(",%d", k5); //以下相似 if (n > 5) printf(",%d", k6); if (n > 6) printf(",%d", k7); if (n > 7) printf(",%d", k8); if (n > 8) printf(",%d", k9); if (n > 9) printf(",%d", k10); printf("\n"); } } return 0;}
运行后果:
办法二。
答案代码:
#include <stdio.h>int main(){ int m, s, i; for (m = 2; m < 1000; m++) { s = 0; for (i = 1; i < m; i++) if ((m % i) == 0) s = s + i; if (s == m) { printf("%d,its factors are", m); for (i = 1; i < m; i++) if (m % i == 0) printf("%d ", i); printf("\n"); } } return 0;}
运行后果:
题目10:有一个分数序列
$$\frac{2}{1},\frac{3}{2},\frac{5}{3},\frac{8}{5},\frac{13}{8},\frac{21}{13}...$$
求出这个数列的前20项之和。
解∶
答案代码:
#include <stdio.h>int main(){ int i, n = 20; double a = 2, b = 1, s = 0, t; for (i = 1; i <= n; i++) { s = s + a / b; t = a, a = a + b, b = t; } printf("sum=%16.10f\n", s); return 0;}
运行后果∶
题目11:一个球从100m高度自在落下,每次落地后反弹回原高度的一半,再落下,再反弹。求它在第 10 次落地时共通过多少米,第 10次反弹多高。
解∶
答案代码;
#include <stdio.h>int main(){ double sn = 100, hn = sn / 2; int n; for (n = 2; n <= 10; n++) { sn = sn + 2 * hn; //第 n次落地时共通过的米数 hn = hn / 2; //第n次反跳高度 } printf("第10次落地时共通过%f米\n", sn); printf("第10次反弹%f米\n", hn); return 0;}
运行后果∶
题目12:猴子吃桃问题。猴子第1天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第 2天早上又将剩下的桃子吃掉一半,又多吃了一个。当前每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,就只剩一个桃子了。求第1天共摘多少个桃子。
解:
答案代码:
#include <stdio.h>int main(){ int day, x1, x2; day = 9; x2 = 1; while (day > 0) //第1天的桃子数是第2天桃子数加1后的2倍 { x1 = (x2 + 1) * 2; x2 = x1; day--; } printf("total=%d\n", x1); return 0;}
运行后果∶
题目13:用迭代法求 $ x=\sqrt{a} $ 。求平方根的迭代公式为
$$x_{n+1} = \frac{1}{2}(x_n)+\frac{a}{x_n}$$
要求前后两次求出的 $ x $ 的差的绝对值小于 $ 10^{-5} $ 。
解:
用迭代法求平方根的算法如下∶
(1)设定一个 $ x $ 的初值 $ x_0 $ ;
(2)用以上公式求出 $ x $ 的下一个值 $ x_1 $ ;
(3)再将 $ x_1 $ 代入以上公式右侧的 $ x_n $ ,求出 $ x $ 的下一个值 $ x_2 $ ;
(4)如此继续下去,直到前后两次求出的 $ x $ 值( $ x $ 和 $ x_n+1 $ )满足以下关系:
$$|x_{n+1} - x_n | \lt 10^{-5}$$
为了便于程序处理,今只用 $ x_0 $ 和 $ x_1 $ ,先令 $ x $ 的初值 $ x_0=a/2 $ (也能够是另外的值),求出 $ x_1 $ ;如果此时 $ |x_1 - x_0| \ge 10^{-5} $ 就使 $ x_1 \Rightarrow x_0 $ ,而后用这个新的 $ x_0 $ 求出下一个 $ x_1 $ ;如此重复,直到 $ |x_1-x_0| \lt 10^{-5} $ 为止。
答案代码:
#include <stdio.h>#include <math.h>int main(){ float a, x0, x1; printf("enter a positive number:"); scanf("%f", &a); x0 = a / 2; x1 = (x0 + a / x0) / 2; do { x0 = x1; x1 = (x0 + a / x0) / 2; } while (fabs(x0 - x1) >= 1e-5); printf("The square root of %5.2f is %8.5f\n", a, x1); return 0;}
运行后果∶
题目14:用牛顿迭代法求上面方程在1.5左近的根:
$$2x^3-4x^2+3x-6=0$$
解:
牛顿迭代法又称牛顿切线法,它采纳以下的办法求根:先任意设定一个与实在的根靠近的值 $ x_0 $ 。作为第 1 次近似根,由 $ x_0 $ 求出 $ f(x_0) $ ,过 $ (x_0, f(x_0)) $ 点做 $ f(x) $ 的切线,交 $ x $ 轴于 $ x_1 $ ,把 $ x_1 $ 作为第 2 次近似根,再由 $ x_1 $ 求出 $ f(x_1) $ ,过 $ (x_1, f(x_1)) $ 点做 $ f(x) $ 的切线,交 $ x $ 轴于 $ x_2 $ ,再求出 $ f(x_2) $ ,再作切线……如此继续下去,直到足够靠近真正的根 $ x^* $ 为止,见图5.4。
从图5.4能够看出:
$$f'(x_0)=\frac{f(x_0)}{x_1-x_0}$$
因而
$$x_1=x_0-\frac{f(x_0)}{f'(x_0)}$$
这就是牛顿迭代公式。能够利用它由 $ x_0 $ 求出 $ x_1 $ ,而后由 $ x_1 $ 求出 $ x_2 $ ……
在本题中:
$$f(x)=2x^3-4x^2+3x-6$$
能够写成以下模式:
$$f(x)=((2x-4)x+3)x-6$$
同样,$ f'(x) $ 可写成:
$$f'(x)=6x^2-8x+3=(6x-8)x+3$$
用这种办法示意的表达式在运算时可节省时间。例如,求 $ f(x) $ 只须要进行 3 次乘法和 3 次加法,而原来的表达式要通过屡次指数运算、对数运算和乘法、加法运算,破费工夫较多。
然而因为计算机的运算速度越来越快,这点工夫开销是微不足道的。这是以前计算机的运算速度较慢时所提出的问题。因为过来编写的程序往往采纳了这种模式,所以在此也顺便介绍一下,以便在浏览他人所写的程序时知其所以然。
答案代码:
#include <stdio.h>#include <math.h>int main(){ double x1, x0, f, f1; x1 = 1.5; do { x0 = x1; f = ((2 * x0 - 4) * x0 + 3) * x0 - 6; f1 = (6 * x0 - 8) * x0 + 3; x1 = x0 - f / f1; } while (fabs(x1 - x0) >= 1e-5); printf("The root of equation is %5.2f\n", x1); return 0;}
运行后果∶
为了便于循环解决,程序中只设了变量 x0 和 x1,x0 代表前一次的近似根,x1代表后一次的近似根。在求出一个x1 后,把它的值赋给x0,而后用它求下一个x1。因为第1次执行循环体时,须要对 x0 赋值,故在开始时应先对 x1 赋一个初值(今为1.5,也能够是靠近实在根的其余值)。
题目15:用二分法求上面方程在(-10,10)的根:
$$2x^3-4x^2+3x-6=0$$
解:
二分法的思路为∶先指定一个区间 $ [x_1,x_2] $ ,如果函数 $ f(x) $ 在此区间是枯燥变动,能够依据 $ f(x_1) $ 和 $ f(x_2) $ 是否同符号来确定方程 $ f(x)=0 $ 在 $ [x_1,x_2] $ 区间是否有一个实根。若 $ f(x_1) $ 和 $ f(x_2) $ 不同符号,则 $ f(x)=0 $ 在 $ [x_1,x_2] $ 区间必有一个(且只有一个)实根; 如果 $ f(x_1) $ 和 $ f(x_2) $ 同符号,阐明在$ [x_1,x_2] $ 区间无实根,要从新扭转 $ x_1 $ 和 $ x_2 $ 的值。当确定 $ [x_1,x_2] $ 有一个实根后,采取二分法将 $ [x_1,x_2] $ 区间一分为二,再判断在哪一个小区间中有实根。 如此一直进行上来,直到小区间足够小为止,见图5.5。
算法如下:
(1)输出 $ x_1 $ 和 $ x_2 $ 的值。
(2)求出 $ f(x_1) $ 和 $ f(x_2) $ 。
(3)如果 $ f(x_1) $ 和 $ f(x_2) $ 同符号,阐明在 $ [x_1,x_2] $ 区间无实根,返回(1),从新输出 $ x_1 $ 和 $ x_2 $ 的值; 若 $ f(x_1) $ 和 $ f(x_2) $ 不同符号,则在 $ [x_1,x_2] $ 区间必有一个实根,执行(4)。
(4)求 $ x_1 $ 和 $ x_2 $ 间的中点:$ x_0=\frac{x_1+x_2}{2} $ 。
(5)求出 $ f(x_0) $ 。
(6)判断 $ f(x_0) $ 和 $ f(x_1) $ 是否同符号。
①如同符号,则应在 $ [x_0,x_2] $ 中去找根,此 时 $ x_1 $ 已 不起作用,用 $ x_0 $ 代替 $ x_1 $,用 $ f(x_0) $ 代替 $ f(x_1) $ 。
②如用 $ f(x_0) $ 与 $ f(x_1) $ 不同符号,阐明应在 $ [x_1,x_0] $ 中去找根,此时 $ x_2 $ 已不起作用,用 $ x_0 $ 代替 $ x_2 $ ,用 $ f(x_0) $ 代替 $ f(x_2) $ 。
(7)判断 $ f(x_0) $ 的绝对值是否小于某一个指定的值(例如 $ 10^{-5}$ )。若不小于 $ 10^{-5}$ ,就返回(4),反复执行(4)、(5)、(6);若小于 $ 10^{-5}$ ,则执行(8)。
(8)输入 $ x_0 $ 的值,它就是所求出的近似根。
N-S图见图5.6。
答案代码:
#include <stdio.h>#include <math.h>int main(){ float x0, x1, x2, fx0, fx1, fx2; do { printf("enter x1 & x2:"); scanf("%f,%f", &x1, &x2); fx1 = x1 * ((2 * x1 - 4) * x1 + 3) - 6; fx2 = x2 * ((2 * x2 - 4) * x2 + 3) - 6; } while (fx1 * fx2 > 0); do { x0 = (x1 + x2) / 2; fx0 = x0 * ((2 * x0 - 4) * x0 + 3) - 6; if ((fx0 * fx1) < 0) { x2 = x0; fx2 = fx0; } else { x1 = x0; fx1 = fx0; } } while (fabs(fx0) >= 1e-5); printf("x=%6.2f\n", x0); return 0;}
运行后果:
题目16:输入以下图案:
* *** ************ ***** *** *
解:
答案代码:
#include <stdio.h>int main(){ int i, j, k; for (i = 0; i <= 3; i++) { for (j = 0; j <= 2 - i; j++) printf(" "); for (k = 0; k <= 2 * i; k++) printf("*"); printf("\n"); } for (i = 0; i <= 2; i++) { for (j = 0; j <= i; j++) printf(" "); for (k = 0; k <= 4 - 2 * i; k++) printf("*"); printf("\n"); } return 0;}
运行后果:
题目17:两个乒乓球队进行较量,各出3人。甲队为A,B,C3人,乙队为X,Y,Z3人。已抽签决定较量名单。有人向队员打听较量的名单,A说他不和 X 比,C说他不和 X,Z比,请编程序找出3对赛手的名单。
解:
先剖析题目。按题意,画出图5.7的示意图。
图5.7中带 $ \times $ 符号的虚线示意不容许的组合。从图中能够看到∶①X既不与 A较量,又不与C较量,必然与B较量。②C既不与X较量,又不与Z较量,必然与Y较量。③剩下的只能是A与Z较量,见图5.8。
以上是通过逻辑推理失去的论断。用计算机程序解决此问题时,不可能立刻就得出结论,而必须对每一种成对的组合一一测验,看它们是否符合条件。 开始时,并不知道A,B,C与X,Y,Z中哪一个较量,能够假如∶A与i较量,B与j较量,C与k 较量,即∶
A—i,
B—j,
C—k
i,j,k别离是X,Y,Z之一,且i,j,k 互不相等(一个队员不能与对方的两人较量),见图5.9。
外循环使 i 由 'X' 变到 'Z' ,中循环使 j 由 'X' 变到 'Z'(但 i 不应与 j 相等)。而后对每一组 i、j 的值,找符合条件的k 值。k 同样也可能是 'X'、'Y'、'Z' 之一,但 k 也不应与 i 或 j 相等。在 i≠j≠k 的条件下,再把 i≠'X' 和 k≠'X' 以及k≠'Z' 的 i,j,k的值输入即可。
答案代码:
#include <stdio.h>int main(){ char i, j, k; // i是a的对手;j是b的对手;k是c的对手 for (i = 'x'; i <= 'z'; i++) for (j = 'x'; j <= 'z'; j++) if (i != j) for (k = 'x'; k <= 'z'; k++) if (i != k && j != k) if (i != 'x' && k != 'x' && k != 'z') printf("A--%c\nB--%c\nC--%c\n", i, j, k); return 0;}
运行后果∶
阐明:
(1)整个执行局部只有一个语句,所以只在语句的最初有一个分号。请读者弄清楚循环和抉择构造的嵌套关系。
(2)剖析最上面一个if语句中的条件;i≠'X',k≠'X',k≠'Z',因为已当时假设 A—i,B—j,C—k,因为题目规定 A不与X反抗,因而i不能等于'X',同理,C不与X,Z反抗,因而k 不应等于'X'和'Z'。
(3)题目给的是 A,B,C,X,Y,Z,而程序中用了加撇号的字符常量'X','Y','Z',这是为什么?这是为了在运行时能间接输入字符A,B,C,X,Y,Z,以示意 3组反抗的状况。