- C语言程序开发范例宝典(软件工程师典藏版)
- 杨丽 郭锐 陈雪峰编著
- 101字
- 2020-06-27 10:54:45
第5章 数学应用
5.1 素数问题
C语言的学习过程中如何解决素数的一系列相关问题是每个初学者都要经历的一个过程,本小节就将介绍有关素数的一些相关问题。
实例135 求100~200的素数
这是一个可以提高分析能力的实例
实例位置:光盘\mingrisoft\05\135
实例说明
求素数表中100~200的全部素数。运行结果如图5.1所示。
图5.1 求100~200的素数
技术要点
素数是大于1的整数,除了能被自身和1整除外,不能被其他正整数整除。本实例的算法是这样的:让i被2 到根号i除,如果i能被2到根号i之中任何一个整数整除,则结束循环,若不能被整除则要判断j是否是最接近或等于根号i的,如果是则证明是素数,否则继续下次循环。
本实例中用到包含在头文件math.h中的函数sqrt。
sqrt函数的一般形式为:
double sqrt(double x)
该函数的作用是返回x的开方值。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件stdio.h和math.h:
#include <stdio.h> #include <math.h>
(3)定义i、j、n为基本整型,并为n赋初值0。
(4)第一个for语句对100到200之间所有数字进行遍历。第二个for语句实现对遍历到数字进行判断,看能否被2到根号i之间的整数整除。
(5)主要程序代码如下:
main() { int i,j,n=0; /*定义变量为基本整型*/ clrscr(); for(i = 100; i <= 200; i++) for(j = 2; j <= sqrt(i); j++) if(i % j==0) /*判断是否能被整除*/ break; /*如果能被整除,就不需要接着判断,跳出循环*/ else if(j > sqrt(i)-1) { printf("%d,", i); n++; /*记录次数*/ if(n % 5==0) /*5个一换行*/ printf("\n"); } else continue; }
举一反三
根据本实例,读者可以:
编写一个判断素数的函数,要求在主函数中输入一个整数,输出该数是否为素数。
用筛选法求1000之内的素数。
实例136 可逆素数
这是一个可以提高分析能力的实例
实例位置:光盘\mingrisoft\05\136
实例说明
可逆素数是指将一个素数的各位数字顺序倒过来构成的反序数仍然是素数。按以上叙述求所有的四位素数。运行结果如图5.2所示。
图5.2 可逆素数
技术要点
本实例的重点是如何求一个数的反序数,方法有很多种,本实例采用了逐位提取数字的方法即对这个四位数采用“%”或“/”的方法分解出每位上的数字。再对重新组合的数字进行判断看是否是素数并判断是否大于原来的四位数(这样做主要是为了防止重复输出例如1031 与1301互可逆素数,这里我们只输出1031即可,1301不必输出)。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件stdio.h和math.h:
#include <stdio.h> #include <math.h>
(3)自定义ss函数,函数类型为基本整型,作用是判断一个数是否为素数。代码如下:
int ss(int i) /*自定义函数判断是否为素数*/ { int j; if(i<=1) /*小于1的数不是素数*/ return 0; if(i==2) /*2是素数*/ return 1; for(j=2;j<i;j++) /*对大于2的数进行判断*/ { if(i % j = = 0) return 0; else if(i != j + 1) continue; else return 1; } }
(4)对1000到10000之间的数进行穷举,找出符合条件的数并将其输出。
(5)主要程序代码如下:
main() { int i, n = 0, n1, n2, n3, n4; clrscr(); for(i = 1000; i < 10000; i++) if(ss(i)= = 1) { n4=i % 10; /*取个位数*/ n3=(i % 100)/10; /*取十位数*/ n2=(i/100)% 10; /*取千位数*/ n1=i/1000; /*取万位数*/ if(ss(1000 *n4 + 100 * n3 + 10 * n2 + n1)= = 1 && 1000 *n4 + 100 * n3 +10*n2+n1>i) /*根据条件判断*/ { printf("%d,", i); n++; /*记录个数*/ if(n % 10==0) /*10个一换行*/ printf("\n"); } } }
举一反三
根据本实例,读者可以:
从键盘中输入一个数,求该数的因子,若因子中有素数,则将这个素数输出,否则给出提示信息。
从键盘中输入一个素数,输出包括该数在内的连续10个素数。
实例137 回文素数
这是一个可以提高分析能力的实例
实例位置:光盘\mingrisoft\05\137
实例说明
任意整数i,当从左向右的读法与从右向左的读法是相同且为素数时则称该数为回文素数,在了解了什么是回文素数的基础上求1000之内的所有回文素数。结果如图5.3所示。
图5.3 回文素数
技术要点
本实例的重点是判断一个数是否是回文素数,因为我们要求输出1000之内的回文素数,那么首先要判断该素数是两位数还是三位数,若是两位数只需判断每位上的数字是否相等便可,若是三位数则需判断个位上和百位上的数字是否相同。相同表明该素数是回文素数,不同则继续下次判断。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件stdio.h:
#include <stdio.h>
(3)自定义ss函数,函数类型为基本整型,作用是判断一个数是否为素数。代码如下:
int ss(int i) /*自定义函数判断是否为素数*/ { int j; if(i<=1) /*小于1的数不是素数*/ return 0; if(i==2) /*2是素数*/ return 1; for(j=2;j<i;j++) /*对大于2的数进行判断*/ { if(i % j = = 0) return 0; else if(i != j + 1) continue; else return 1; } }
(4)对10到1000之间的数进行穷举,找出符合条件的数并将其输出。
(5)主要程序代码如下:
main() { int i; for(i = 10; i < 1000; i++) if(ss(i)==1) /*判断是否是素数*/ if(i/100==0) /*判断是否是两位数*/ { if(i/10==i % 10) /*判断十位和各位是否相同*/ printf("%5d", i); } else if(i/100==i % 10) /*判断百位和个位是否相同*/ printf("%5d", i); }
举一反三
根据本实例,读者可以:
从键盘中输入一个数,判断该数是否是回文素数。
从键盘中任意输入一个回文素数,输出包括该数在内的连续5个回文素数。
5.2 整数趣题
在学习过程中会发现许多数之间都有着内在联系,如果想找出存在相同规律的一组数,光凭用笔来算会花费大量的时间,且很容易漏掉某个数,如果用编程的方法来找具有相同规律的一组数,不但简单、方便、快捷而且不会漏掉任何一个数。本小节就将介绍有关整数的一些相关实例。
实例138 阿姆斯特朗数
这是一个可以提高分析能力的实例
实例位置:光盘\mingrisoft\05\138
实例说明
阿姆斯特朗数也就是俗称的水仙花数,是指一个3位数,其各位数字的立方和等于该数本身。例如153是一个水仙花数,因为153=13+53+33。编程求出所有水仙花数。运行结果如图5.4所示。
技术要点
本题采用穷举法对100~1000的数字进行拆分,再按照阿姆斯特朗数(水仙花数)的性质计算并判断,满足条件的输出,否则进行下次循环。
图5.4 阿姆斯特朗数
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h>
(3)使用for语句对100~1000的数进行穷举。
(4)主要程序代码如下:
main() { int i,j,k,n; /*定义变量为基本整型*/ for(i=100;i<1000;i++) /*对100~1000的数进行穷举*/ { j=i % 10; /*分离出个位上的数*/ k=i/10 % 10; /*分离出十位上的数*/ n=i/100; /*分离出百位上的数*/ if(j*j*j+k*k*k+n*n*n==i) /*判断各位上的立方和是否等于其本身*/ printf("%5d",i); /*将水仙花数输出*/ } }
举一反三
根据本实例,读者可以:
自定义一个函数judge()用来判断输入的任意一个数是否是水仙花数。
找出10~100的数n,能满足其各位数的平方和小于该数本身。
实例139 特殊的完全平方数
本实例是一个提高基础技能的程序
实例位置:光盘\mingrisoft\05\139
实例说明
在3位整数100~999中找符合如下条件的整数并将其输出在屏幕上,条件如下:要求这个数既是完全平方数,又有两位数字相同,如121、144等。运行结果如图5.5所示。
图5.5 数字检测
技术要点
本实例的算法思想如下:对探测到的100~999的数首先要判断它是不是完全平方数,如果是完全平方数再分离出其百位、十位、个位上的数字,再用if条件判断语句判断分离出的3个数中是否有两个数相同。如果有两个数相同则输出该数字,否则继续下次循环。如果不是完全平方数就不用分离再判断直接进行下次探测便可。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h>
(3)用while循环判断探测到的数据是否是完全平方数,如果是再进一步分离各位上的数据,判断是否有两个是相同的,如果有则输出,否则进行下次循环。
(4)主函数程序代码如下:
main() { int i, j; int hun,ten,data; /*定义变量存储分解出的百位、十位、个位*/ printf("the result is:\n"); for(i = 100; i <= 999; i++) { j = 10; while(j *j <= i) { if(i = = j *j) { hun=i/100; /*分解出百位上的数*/ data = i - hun * 100; ten=data/10; /*分解出十位上的数*/ data=data-ten*10; /*分解出个位上的数*/ if(hun==ten||hun==data||ten==data)/*判断分解出的三个数中是否有两个数是相等的*/ printf("%5d",i); /*将符合条件的数输出*/ } j++; } } }
举一反三
根据本实例,读者可以:
编程输出有两位相同数字的所有三位数。
从键盘中任意输入一组数字序列,再输入一个数字,查找该数字在该数字序列中出现的次数。
实例140 求1000以内的完全数
这是一个可以提高分析能力的实例
实例位置:光盘\mingrisoft\05\140
实例说明
如果一个数恰好等于它的因子之和,这个数就称为“完全数”。例如6的因子是1、2、3,而6=1+2+3,因此6是“完全数”。编程求出1000以内的所有完全数。运行结果如图5.6所示。
图5.6 完全数
技术要点
本实例采用穷举的方法对1000 以内的数逐个求因子再求和看是否等于该数,如果相等则输出该数,否则进行下次循环。这里要强调的是求一个数i因子的方法即用该数i对从1到i−1的所有数取余,看余数是否为0,如果为0则说明该数是i的因子。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h>
(3)定义i、j、sum为基本整型,并为sum赋初值0。
(4)对1到1000之间的数按照完全数的要求进行运算并判断,并将最终符合要求的结果输出。
(5)主要程序代码如下:
main() { int i,j,sum=0; /*定义变量为基本整型*/ for(i=1;i<1000;i++) /*对1000以内的数进行穷举*/ { sum = 0; for(j = 1; j < i; j++) if(i % j==0) /*判断j是否是i的因子*/ sum+=j; /*因子相加求和*/ if(sum==i) /*判断该数是否等于各因子之和*/ printf("%4d", i); } }
举一反三
根据本实例,读者可以:
自定义一个函数judge()用来判断输入的任意一个数是否是完全数。
任意输入一个数,若该数的因子是素数则将其因子输出,否输出提示信息。
实例141 三重回文数
本实例是一个提高基础技能的程序
实例位置:光盘\mingrisoft\05\141
实例说明
找出10~1000之间的数n,它满足n、n2、n3均为回文数。回文数指其各位数字左右对称的整数。运行结果如图5.7所示。
图5.7 三重回文数
技术要点
本实例判断回文数的方法和以往用的逐位分离在判断的方法不同,实例中是将一个数转换成字符串存到字符型数组a中,再对这个数组做判断看其是否在对应位置相等,如在对应位置均相等则说明是回文数,只要有一个不相等则说明不是回文数。
实例中用到了函数ltoa(),下面对其使用方法进行具体说明:
char *ltoa(long num,char *str,int radix)
该函数的作用是把长整数num转换成其等价的字符串,并且把结果存到由str所指向的字符串中,字符串输出的进制数是由radix确定的,它一般在2~36的范围内变化。返回指向str的指针。该函数的原型在stdlib.h中。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h> #include <stdlib.h>
(3)自定义judge()函数,用来判断一个数是否是回文数。代码如下:
int judge(long n) /*判断一个数是否是回文数*/ { int i,len,half; /*定义变量为基本整型*/ char a[20]; /*定义数组a为字符型*/ ltoa(n,a,10); /*把长整形数n转换成字符串存到数组a中*/ len=strlen(a); /*获取数组a的长度*/ half = len / 2; for(i = 0; i < half; i++) if(a[i] != a[--len]) /*判断相对应位置的字符是否相同*/ break; /*如果不想同跳出循环*/ if(i >= half) return 1; /*是回文数返回1*/ else return 0; /*不是回文数返回0*/ }
(4)主函数程序代码如下:
main() { long n; clrscr(); printf("the result is:\n"); for(n = 11; n < 1000; n++) /*对10~1000之间的数进行判断*/ if(judge(n)&& judge(n *n)&& judge(n *n * n)) /*判断是否是三重回文数*/ printf(" n=%4ld,n*n=%6ld,n*n*n=%8ld \n", n, n *n, n *n * n); /*将三重回文数输出*/ getch(); }
举一反三
根据本实例,读者可以:
输出10~1000之间二重回文数。
用逐位分离的方法求三重回文数。
实例142 亲密数
这是一个可以提高分析能力的实例
实例位置:光盘\mingrisoft\05\142
实例说明
如果整数A的全部因子(不包括1和A)之和等于B,且整数B的全部因子(不包括1和B)之和等于A,则将A和B称为亲密数。求10000以内的所有亲密数。运行结果如图5.8所示。
图5.8 亲密数
技术要点
本实例采用穷举的方法对10000以内的数逐个求因子并求出所有因子之和sum1,再对所求出的和sum1求因子并再次求所有因子之和sum2,此时按亲密数的要求进行进一步筛选便求出最终结果。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h>
(3)定义i、j、k、sum1和sum2为基本整型。
(4)对1到10000之间的数按照技术要点中所提到的过程进行运算并判断,并将最终符合要求的结果输出。这里求因子的方法依旧是用数i对从1到i−1的所有数取余,看余数是否为0,如果为0则说明该数是i的因子。
(5)主要程序代码如下:
main() { int i,j,k,sum1,sum2; /*定义变量为基本整型*/ for(i=1;i<=10000;i++) /*对10000以内的数进行穷举*/ { sum1 = 0; sum2 = 0; for(j = 1; j < i; j++) if(i % j==0) /*判断j是否是i的因子*/ sum1+=j; /*求因子的和*/ for(k = 1; k < sum1; k++) if(sum1 % k==0) /*判断k是否是sum1的因子*/ sum2+=k; /*求因子和*/ if(sum2 = = i && i != sum1 && i < sum1) printf("\n%5d=>%5d",i,sum1); /*将亲密数输出*/ } }
举一反三
根据本实例,读者可以:
在本题基础上用自定义函数的方法来求亲密数。
编程求古稀数。
实例143 自守数
这是一个可以提高分析能力的实例
实例位置:光盘\mingrisoft\05\143
实例说明
自守数是指一个数平方的尾数等于该数自身的自然数。下列数字便是自守数:
252=625
762=5776
93762=87909376
编程求100000以内的所有自守数。运行结果如图5.9所示。
图5.9 自守数
技术要点
解本题的关键是分析其手工求解过程中的规律,下面就来具体分析:
观察上式发现9376×9376的最终结果是87909376,这里我们关心积的后四位是如何产生的,具体规律如下。
● 第一部分积(56256):被乘数的最后四位乘以乘数的倒数第一位。
● 第二部分积(65632):被乘数的最后三位乘以乘数的倒数第二位。
● 第三部分积(28128):被乘数的最后两位乘以乘数的倒数第三位。
● 第四部分积(84384):被乘数的最后一位乘以乘数的倒数第四位。
将以上四部分的后四位求和后,取后四位便可求出一个四位数乘积的后四位。其他不同位数的数依此类推。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include<stdio.h>
(3)定义i、j、k、sum1和sum2为基本整型。
(4)对1到10000之间的数按照亲技术要点中所提到的过程进行运算并判断,并将最终符合要求的结果输出。这里求因子的方法依旧是用该数i对从1到i−1的所有数取余,看余数是否为0,如果为0则说明该数是i的因子。
(5)主要程序代码如下:
main() { long i, j, k1, k2, k3, a[10] = { 0 } ,num,m,n,sum; /*定义变量及数组为长整形*/ printf("please inpput a number:\n"); scanf("%ld",&num); /*从键盘中输入要求的范围*/ printf("the result is:"); for(j=0;j<num;j++) /*对该范围内的数逐个试探*/ { m = j; n = 1; sum = 0; k1 = 10; k2 = 1; while(m!=0) /*判断该数的位数*/ { a[n]=j % k1; /*分离出的数存入数组中*/ n++; /*记录位数,实际位数为n-1*/ k1*=10; /*最小n位数*/ m = m / 10; } k1 = k1 / 10; k3 = k1; for(i = 1; i <= n -1; i++) { sum+=(a[i]/k2*a[n-i])% k1*k2; /*求每一部分积之和*/ k2 *= 10; k1 /= 10; } sum=sum % k3; /*求和的后n-1位*/ if(sum = = j) printf("%8ld",sum); /*输出找到的自守数*/ } }
举一反三
根据本实例,读者可以:
输入两个数,如果这两个数相乘的积后两位数是奇数,则输出它们的积,否则输出这两个数的和。
输入两个数,如果两个数的差是素数,则输出从该素数开始的连续5个素数。
实例144 满足abcd=(ab+cd)2的数
这是一个可以提高基础技能的实例
实例位置:光盘\mingrisoft\05\144
实例说明
假设abcd是一个四位整数,将它分成两段,即ab和cd,使之相加求和后再平方。求满足该关系的所有四位整数。运行结果如图5.10所示。
图5.10 满足abcd=(ab+cd)2的数
技术要点
本实例采用穷举的方法对10 00到10000以内的所有四位整数逐个分解成两部分再对其进行判断,看是否满足要求,如果满足则将该整数输出,否则进行下次循环。将一个四位数分解成两部分主要采用“/”和“%”的方法,“/”求该四位数的前两位,“%”求该四位数的后两位。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h>
(3)定义i、a和b为基本整型。
(4)使用for循环对1000到10000之间所有的四位正整数按照技术要点中所提到的过程进行分解并判断,并将最终符合要求的结果输出。
(5)主要程序代码如下:
main() { int i,a,b; /*定义变量为基本整型*/ for(i=1000;i<10000;i++) /*对1000~10000间数进行穷举*/ { a=i/100; /*求出该数的前两位数*/ b=i % 100; /*求出该数的后两位数*/ if((a+b)*(a+b)==i) /*判断是否满足条件*/ printf("\n%5d", i); } }
举一反三
根据本实例,读者可以:
编程产生10个1000以内互不相同的数。
编程验证大于1000的奇数其平方与1的差是8的倍数。
实例145 神奇的数字6174
这是一个可以启发思维的实例
实例位置:光盘\mingrisoft\05\145
实例说明
从键盘中任意输入一个四位数,要求该四位数各个位上的数字是不相同的,将组成该四位数的四个数字由大到小排列,形成由这四个数组成的最大四位数;再由小到大排列,形成由这四个数组成的最小四位数(如果数字中有0,则得到不足四位的数);求这个最大数与最小数的差,重复以上过程,最终得到的结果总是6174。运行结果如图5.11所示。
技术要点
编写程序时,只需按照题中给的条件一步一步来做,便可实现最终的功能。程序中,将数组中的四个数由小到大排序采用了选择排序法,这里读者也可采用其他方法,简单实用便可。四位数的分离使用“/”和“%”便可实现。
图5.11 神奇的数字6174
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件stdio.h:
#include <stdio.h>
(3)自定义difference()函数,实现求该四位数组成的最大四位数与最小数的差,代码如下:
int difference(int a[]) /*自定义difference函数实现求最大数与最小数的差*/ { int t, i, j, sum, sum1, sum2; for(i=0;i<3;i++) /*利用选择排序法对数组a中的数据由大到小排序*/ for(j = i + 1; j < 4; j++) if(a[i] < a[j]) { t = a[i]; a[i] = a[j]; a[j] = t; } sum1=a[0]*1000+a[1]*100+a[2]*10+a[3]; /*将数组中的四个数组成最大四位数*/ sum2=a[3]*1000+a[2]*100+a[1]*10+a[0]; /*将数组中的四个数组成最小n位数,n小于等于4*/ sum=sum1-sum2; /*求最大数与最小数的差*/ printf("%5d=%5d-%5d\n",sum,sum1,sum2); /*讲求的的结果按指定格式输出*/ return sum; /*将差值返回*/ }
(4)主函数程序代码如下:
main() { int i, j, k, l, n, a[4]; printf("please input a number:\n"); scanf("%d",&n); /*从键盘中输入一个四位数*/ while(n != 6174) { a[0]=n/1000; /*分离出千位上的数*/ a[1]=n/100 % 10; /*分离出百位上的数*/ a[2]=n/10 % 10; /*分离出十位上的数*/ a[3]=n % 10; /*分离出个位上的数*/ n=difference(a); /*调用difference函数,将返回值赋给n*/ } }
举一反三
根据本实例,读者可以:
求出1~1000之内能被7或11整除,但不能同时被7和11整除的所有整数。
将输入的两个两位整数a和b合并成一个新的整数c,a的十位是c的百位,a的个位是c的千位,b的十位是c的个位,b的个位是c的十位。
实例146 一数三平方
这是一个可以启发思维的实例
实例位置:光盘\mingrisoft\05\146
实例说明
有这样一个六位数,它本身是一个整数的平方,其高三位和低三位也分别是一个整数的平方,例如225625=4752、225=152、625=252,求满足上述条件的所有六位数。运行结果如图5.12所示。
图5.12 一数三平方
技术要点
要实现本题目中的要求有许多方法,本实例也只是其中的一种,下面来介绍具体的求解思路:程序中用到了sqrt函数,该函数的一般形式如下:
double sqrt(double num)
函数的作用是返回参数num的平方根,这里我们可以发现sqrt的返回值是一个double型,程序中我们将sqrt的返回值强制转换成长整形,这样会使开平方后得到的小数(小数点后不为0)失去其小数点后面的部分,那么再对这个强制转换后的数再平方,所得的结果将不会等于原来开平方前的数。若开平方后得到的小数其小数点后的部分为0,则将其强制转换为长整型也不会产生数据流失,那么再对这个强制转换后的数再平方,所得的结果就将等于原来开平方前的数。我们利用这个方法就能很好地判断出一个数开平方后得到的数是否是整数。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件stdio.h:
#include <stdio.h> #include <math.h>
(3)利用for循环对100000~999999之间的所有数按照题中所要求的条件进行试探,对满足条件的数将其输出到屏幕上,并用变量count记录满足条件的数的个数。
(4)主函数程序代码如下:
main() { long i,n,n1,n2,n3,n4,count=0; /*定义变量为长整形*/ printf("the result is:\n"); for(i=100000;i<=999999;i++) /*遍历所有的六位数*/ { n=(long)sqrt(i); /*对i值开平方得到一个长整型数值n*/ if(i==n*n) /*判断n的平方是否等于i*/ { n1=i/1000; /*求出高三位数*/ n2=i % 1000; /*求出低三位数*/ n3=(long)sqrt(n1); /*对n1值开平方得到一个长整型数值n3*/ n4=(long)sqrt(n2); /*对n2值开平方得到一个长整型数值n4*/ if(n1 = = n3 *n3 && n2 = = n4 *n4) /*判断是否同时满足n1等于n3的平方,n2等于n4的平方*/ { count++; /*count作为计数器,记录满足条件的个数*/ printf("%ld,", i); } /*将最终满足条件的i值输出*/ } } printf("\ntotal is:\n%d",count); /*输出满足条件的个数*/ }
举一反三
根据本实例,读者可以:
在了解本程序的基础上用另一种方法进行编程。
编程求十数字组四个平方数。
5.3 数学问题求解
学习计算机或数学专业的人都知道这样一句话:“计算机和数学不分家”,这句话很好地说明了计算机和数学的关系是十分紧密的,因为数学中的很多问题都可以通过编程来解决,本小节就介绍了几个用编程解决数学问题的实例。
实例147 求等差数列
这是一个可以提高分析能力的实例
实例位置:光盘\mingrisoft\05\147
实例说明
幼儿园老师给学生由前向后发糖果,每个学生得到的糖果数目成等差数列,前四个学生得到的糖果数目之和是26,积是880,编程求前20名学生每人得到的糖果数目。运行结果如图5.13所示。
图5.13 求等差数列
技术要点
在编写程序前,要先确定这个等差数列的首项及公差的取值范围,因为数字比较小范围确定读者可通过手工来算,很容易确定出等差数列首项的范围是1~6(不包括6),公差的取值范围是1~4(不包括4),在确定了首项和公差之后便可按照题意设置条件进行判断。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h>
(3)定义i、j、number及n分别为基本整型。
(4)使用for语句进行穷举,对满足if语句中的条件按指定的格式输出,否则进行下次循环。
(5)主要程序代码如下:
main() { int i, j, number, n; for(number=1;number<6;number++) /*对1到5之间的数进行穷举*/ for(n=1;n<4;n++) /*对1到3之间的数进行穷举*/ if((4 *number + 6 * n = = 26)&&(number *(number + n)*(number + 2 * n)* (number+3*n))==880) /*判断是否满足题中条件*/ { printf("The result is:\n"); for(j = 1; j <= 20; j++) { printf("%3d", number); number += n; if(j % 5==0) /*每输出5个进行换行*/ printf("\n"); } } }
举一反三
根据本实例,读者可以:
计算多项式p(x)=an-1xn-1+an-2xn-2+…+a1x+a0在指定点x处的函数值。
有一个等差数列,它的前4项之和是46,积是14560,求该等差数列的前10项。
实例148 求整数的绝对值
这是一个可以提高基础技能的实例
实例位置:光盘\mingrisoft\05\148
实例说明
编程实现从键盘上任意输入一个整数,在屏幕中显示出其相应的绝对值。运行结果如图5.14所示。
图5.14 求整数的绝对值
技术要点
● abs函数
一般形式:
int abs(int x)
该函数的功能是求整数的绝对值,参数x是所要求绝对值的整数。
在了解了abs函数的基础上这里还要给读者介绍两个函数,labs函数及fabs函数。
● labs函数
一般形式:
long labs(long x)
该函数的功能是求长整型整数的绝对值,参数x是所要求绝对值的整数。
● fabs函数
一般形式:
double fabs(double x)
该函数的功能是求浮点数的绝对值,参数x是所要求绝对值的整数。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件stdio.h和math.h:
#include <stdio.h> #include <math.h>
(3)从键盘中任意输入一个数,调用abs函数求出其绝对值并输出。
(4)主要程序代码如下:
main() { int i; /*定义变量i为基本整型*/ printf("please input a number:\n"); /*双引号内普通字符原样输出并回车*/ scanf("%d",&i); /*从键盘中输入数值并赋值给i*/ printf("number:%d,absolute value:%d",i,abs(i)); /*调用abs函数求出绝对值*/ }
举一反三
根据本实例,读者可以:
编程实现求一个浮点数的绝对值。
不用abs函数,用条件语句实现求一个整数的绝对值。
实例149 正弦、余弦、正切值
这是一个可以提高基础技能的实例
实例位置:光盘\mingrisoft\05\149
实例说明
编程实现从键盘上任意输入一个整数,在屏幕中显示出其相应的正弦值、余弦值以及正切值。运行结果如图5.15所示。
图5.15 正弦、余弦、正切值
技术要点
● sin函数
一般形式:
double sin(double x)
该函数的功能是返回参数x的正弦值,这里x用弧度表示。
● cos函数
一般形式:
double cos(double x)
该函数的功能是返回参数x的余弦值,这里x用弧度表示。
● tan函数
一般形式:
double tan(double x)
该函数的功能是返回参数x的正切值,这里x用弧度数表示。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件stdio.h和math.h:
#include <stdio.h> #include <math.h>
(3)从键盘中任意输入一个数,调用sin函数、cos函数及tan函数分别求出其对应的数值并输出。
(4)主要程序代码如下:
main() { float n; /*定义n为单精度型*/ printf("please input:\n"); /*双引号内普通字符原样输出并回车*/ scanf("%f",&n); /*从键盘中输入一个单精度数并赋给n*/ printf("the sin of %f is %f\n",n,sin(n)); /*调用sin函数输出正弦值*/ printf("the cos of %f is %f\n",n,cos(n)); /*调用cos函数输出余弦值*/ printf("the tan of %f is %f\n",n,tan(n)); /*调用tan函数输出正弦值*/ }
举一反三
根据本实例,读者可以:
分别利用asin函数、acos函数及atan函数求输入的任意数的反正弦、反余弦及反正切值。
利用cosh函数、tanh函数求输入的任意数的双曲余弦、双曲正切。
实例150 自然对数的底e的计算
这是一个可以提高基础技能的实例
实例位置:光盘\mingrisoft\05\150
实例说明
自然对数的底e=2.718281828……e的计算公式是:
e=1+1/1!+1/2!+1/3!+……要求当最后一项的值小于10-10时结束。运行结果如图5.16所示。
图5.16 自然对数的底e的计算
技术要点
仔细观察e的计算公式,会发现想求出最终结果关键是求每一项所对应的阶乘。本程序中使用while循环,循环体中实现累加求和并在求和之后求下一项乘所对应的阶乘。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h>
(3)使用while实现累加求和并在求和之后求下一项的所对应的阶层。
(4)主要程序代码如下:
main() { float e=1.0,n=1.0; /*定义e和n为单精度型,并为它们赋初值为-1*/ int i=1; /*定义i为基本整型并赋初值为1*/ while(1/n>1e-10) /*当该项的值不小于10-10时,执行循环体中内容*/ { e+=1/n; /*累加各项的和*/ i++; n=i*n; /*求阶层*/ } printf("the value of e is %f",e); /*将最终结果输出*/ }
举一反三
根据本实例,读者可以:
编程求lgx。
编程求10x。
实例151 最大公约及最小公倍数
这是一个可以启发思维的实例
实例位置:光盘\mingrisoft\05\151
实例说明
从键盘中输入两个正整数a和b,求其最大公约数和最小公倍数。运行结果如图5.17所示。
图5.17 最大公约及最小公倍数
技术要点
在算两个数的最大公约数时,我们通常采用辗转相除的方法,本实例也就是将辗转相除的过程用C语言语句表示出来。最小公倍数和最大公约数之间的关系是:两数相乘的积除以这两个数的最大公约数就是最小公倍数。知道这层关系后用辗转相除法求出最大公约数,那么最小公倍数也便求出来了。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件stdio.h:
#include <stdio.h>
(3)使用scanf函数将输入的两个数分别赋值给a和b,如果a小于b则借助中间变量t将a与b的值互换,用辗转相除的方法求出a和b的最大公约数,进而求出最小公倍数并将它们输出。
(4)主要程序代码如下:
main() { int a,b,c,m,t; /*定义变量为基本整型*/ printf("please input two numbers;\n"); scanf("%d%d",&a,&b); /*从键盘中输入两个数*/ if(a<b) /*当a小于b时实现俩值互换*/ { t = a; a = b; b = t; } m=a*b; /*求出a与b的乘积*/ c=a%b; /*a对b取余赋给c*/ while(c!=0) /*当c不为0时执行循环体语句*/ { a=b; /*将b赋给a*/ b=c; /*将c的值赋给b*/ c=a%b; /*继续取余并赋给c*/ } printf("the max commen divisor:\n%d\n",b); /*输出最大公约数*/ printf("the min commen multiple:\n%d",m/b); /*输出最小公倍数*/ }
举一反三
根据本实例,读者可以:
从键盘中任意输入3个数,编程求这3个数的最大公约数。
从键盘中任意输入3个数,编程求这3个数的最小公倍数。
实例152 求解二元一次不定方程
这是一个可以提高分析能力的实例
实例位置:光盘\mingrisoft\05\152
实例说明
求解二元一次不定方程ax+by=c的解,其中a、b、c要求从键盘中输入,其中a>0,b>0且a≥b。运行结果如图5.18所示。
图5.18 求解二元一次不定方程
技术要点
关于求解二元一次不定方程ax+by=c有两个重要的结论。
● 二元一次不定方程有解的充分必要条件是a与b的最大公约数能整除c。
● 如果(x0,y0)是方程的一组解,则对任何整数k,(x0+bk,y0-ak)也都是方程的解。
下面以123x+35y=7来分析下二元一次不定方程的求解算法:
123=35×3+18
35=18×1+17
18=17×1+1
17=1×17
将上述推导过程用公式表示出来便是:
an=bn×cn+dn,cn=an/bn,dn=an%bn,an+1=bn,bn+1=dn
x[n]、y[n]的递推计算公式如下:
x[0]=0,x[1]=1,x[n+1]=x[n] ×q[n]+x[n-1](i>1)
y[0]=1,y[1]=q[0],y[n+1]=y[n] ×q[n]+y[n-1](i>1)
最终方程的解便是x=(-1)n-1x[n],y=(-1)ny[n],这里n的值就是进行计算的轮数。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h>
(3)自定义result()函数,用来求解二元一次不定方程的一组解,代码如下:
void result(int a,int b,int c,int*x2,int*y2) /*自定义函数解*/ { int x[100], y[100], z[100]; int i, j, d, t, gcd; x[0] = 0; y[0] = 1; for(i = 0; i < 100; i++) { z[i]=a/b; /*求a/b的值*/ d=a%b; /*求a对b取余的值*/ a = b; b = d; if(d = = 0) { gcd=a; /*辗转法求最大公约数*/ break; } if(i==0) /*判断a是否能被b整除*/ { x[1] = 1; y[1] = z[0]; } else { x[i + 1] = z[i] *x[i] + x[i -1]; y[i + 1] = z[i] *y[i] + y[i -1]; } } for(t= -1,j=1;j<i;j++) t= -t; *x2= -t*x[i]; *y2=t*y[i]; /*求出ax+by=gcd(a,b)的一组解*/ if(c % gcd!=0) /*如果c能否整除a和b的最大公约数*/ { printf("No solution!\n"); /*如不能整除,则输出无解的提示信息*/ exit(0); } t=c/gcd; /*若能整除则将结果赋给t*/ *x2= *x2*t; *y2= *y2*t; }
(4)自定义test()函数,用来检验求出的解是否满足方程,代码如下:
void test(int a,int b,int c,int x,int y) /*自定义函数检测求出的结果*/ { if(a*x+b*y==c) /*将x、y带进整式看是否等于c*/ printf("Result right!\n"); else printf("Result error!\n"); }
(5)主要程序代码如下:
main() { int a, b, c, x2, y2; printf("input a,b,c:\n"); /*输入a、b、c的值*/ scanf("%d%d%d", &a, &b, &c); result(a,b,c,&x2,&y2); /*调用函数求出解*/ test(a,b,c,x2,y2); /*检验结果是否正确*/ printf("x=%d,y=%d\n",x2,y2); /*将x、y的值输出*/ }
举一反三
根据本实例,读者可以:
编程实现线性方程组求解。
编程实现用高斯消去法求解实系数方程组。
实例153 二分法求解方程
这是一个可以提高分析能力的实例
实例位置:光盘\mingrisoft\05\153
实例说明
用二分法解方程sin(x)=0在(1.5,4.5)之间的根,要求区间范围从键盘中输入。运行结果如图5.19所示。
图5.19 二分法求解方程
技术要点
二分法解方程的思路如下:如果函数(f x)在指定区间[x1,x2]内具有单调性,当 f(x1)与 f(x2)异号时,说明方程 f(x)=0在区间[x1,x2]内有且仅有一个实根,当f(x1)和f(x2)同号时,方程f(x)=0在区间[x1,x2]内无实根。当确定在[x1,x2]内有一个实根后,便采用二分法将[x1,x2]分成两部分,再确定实根在哪一个小区间中,依此类推,不断进行下去,直到分成的区间足够小为止。
算法如下。
(1)首先输入区间的范围[x1,x2]。
(2)求出 f(x1)及 f(x2)的值并判断是否异号,如果同号则说明在该区间内无实根,输出提示信息结束程序,否则继续进行步骤3。
(3)求x1和x2的中点x0并求出f(x0)的值。
(4)判断f(x0)与f(x1)是否同号,如果同号则根应在[x0,x2]中,否则说明根应在[x1,x0]中。
(5)判断f(x0)的绝对值是否小于指定的精度,若不小于则跳转到步骤(3),按照上面的流程继续执行,直到f(x0)的绝对值小于指定的精度,此时输出x0的值,该值便是所要求的近似根。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <math.h> #include <stdio.h>
(3)程序用do…while语句判断输入的区间内是否有根,若无根则需重新输入范围,若有根则采用了二分法求解方程的根。
(4)主要程序代码如下:
main() { float x0,x1,x2,f0,f1,f2; /*定义变量为浮点型*/ do { printf("enter x1,x2:"); scanf("%f,%f",&x1,&x2); /*从键盘中输入范围*/ f1 = sin(x1); f2 = sin(x2); } while(f1*f2>0); /*判断是否有根,若无根重新输入范围*/ do { x0=(x1+x2)/2; /*取中间值*/ f0=sin(x0); /*求f0*/ if((f0*f1)<0) /*判断根在那个范围内*/ { x2=x0; /*范围在(x1,x0)*/ f2 = f0; } else { x1=x0; /*范围在(x0,x1)*/ f1 = f0; } } while(fabs(f0)>=1e-5); /*判断是否大于精度*/ printf("x=%6.2f\n",x0); /*将最终结果输出*/ }
举一反三
根据本实例,读者可以:
编程实现用追赶法求解三对角线方程组。
编程实现用平方根法求解对称正定方程组。
实例154 牛顿迭代法解方程的根
这是一个可以提高分析能力的实例
实例位置:光盘\mingrisoft\05\154
实例说明
用牛顿迭代法求根。方程为ax3+bx2+cx+d=0,系数a、b、c、d的值从键盘中输入,求x在1.5附近的一个实根。运行结果如图5.20所示。
图5.20 迭代法解方程的根
技术要点
牛顿迭代法又称牛顿切线法,它的求根方法如下:先任意设定一个与真实的根接近的值x0作为第一次近似根,由x0求出f(x0),过(x0,f(x0))点做f(x)的切线,交x轴于x1,把它作为第二次近似根;再由x1求出求出f(x1),过(x1,f(x1))点做f(x)的切线,交x轴于x2,求出f(x2);再做切线……依此类推,直到极为接近真正的根xn为止,因此得出牛顿迭代公式:x1=x0-f(x0)/f′(x0)。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h> #include <math.h>
(3)自定义Newton()函数,该函数功能是实现迭代法求方程的根,代码如下:
float Newton(float a,float b,float c,float d) /*自定义函数Newton,实现迭代法解方程*/ { float x=1,x0,f,f1; /*定义变量类型为单精度型*/ do { x0 = x; f=((a*x0+b)*x0+c)*x0+d; /*求f(x0)*/ f1=(3*a*x0+2*b)*x0+c; /*求f(x0)的导数*/ x=x0-f/f1; /*套用牛顿迭代公式*/ } while(fabs(x-x0)>=1e-5); /*迭代到指定精度*/ return(x); /*返回x的值*/ }
(4)主函数程序代码如下:
main() { float a, b, c, d; scanf("%f%f%f%f",&a,&b,&c,&d); /*从键盘中输入系数*/ printf("%.2fx^3+%.2fx^2+%.2fx+%.2f=0\n",a,b,c,d); /*输出方程*/ printf("x=%.5f\n",Newton(a,b,c,d)); /*输出根*/ }
举一反三
根据本实例,读者可以:
编程实现用梯度法求解非线性方程组一组实根。
编程实现用牛顿下山法求实系数代数方程全部根。
5.4 矩阵
本节主要介绍一些矩阵相关的操作,例如打印特殊方阵、矩阵乘法、矩阵加法等,读者可以通过对本小节实例的学习,对矩阵的运算及打印有个一个初步的认识,在今后编程过程中遇到类似题便会迎刃而解。
实例155 打印特殊方阵
这是一个可以启发思维的实例
实例位置:光盘\mingrisoft\05\155
实例说明
打印特殊方阵,具体要求如下:打印9×9 阶的方阵,要求最外圈均是1,次外圈均是2,照此规律方阵最中间数字是5,运行结果如图5.21所示。
图5.21 打印特殊方阵
技术要点
根据题意,我们会发现该方阵上下左右是相互对称的,只要找出最外圈的是按什么规律构造的,也便找出了整个方阵的构造的规律,下面以最外圈为例分析。二维数组a[i][j]其中i为1即行为1,j也代表了列从1变换到9,这表示了整个方阵的最上面一行;a[10-i][j]中行为9,列从1变化到9,这表示了整个方阵的最下面一行;a[j][i]中行从1变化到9,列为1,则表示了整个方阵的最左面一列;a[j][10-i]中行从1变化到9,列为9,这表示了整个方阵的最右面一列。按此规律,整个方阵便可构造出来。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h>
(3)定义i、j及二维数组a[10][10]分别为基本整型。
(4)使用for循环,结合技术要点中分析的规律构造这个特殊方阵。
(5)主要程序代码如下:
main() { int a[10][10],i,j; /*定义数组及变量为基本整型*/ for(i = 1; i <= 5; i++) for(j = i; j <= 10-i; j++) { a[i][j]=i; /*方阵中每次相对的上面一行等于i*/ a[10-i][j]=i; /*方阵中每次相对的下面一行等于i*/ a[j][i]=i; /*方阵中每次相对的左面一列等于i*/ a[j][10-i]=i; /*方阵中每次相对的右面一列等于i*/ } for(i = 1; i <= 9; i++) { for(j = 1; j <= 9; j++) printf("%3d",a[i][j]); /*将该方阵输出*/ printf("\n"); /*每输完一行进行换行*/ } }
举一反三
根据本实例,读者可以:
要求从键盘中输入7,输出题中要求的特殊方阵,此时方阵中间数应为7。
要求打印特殊方阵,该特殊方阵与题中要求方阵类似,不同之处,要求最外圈为5,次外圈为4,依此类推直至最中间数字为1。
实例156 求3×3矩阵对角元素之和
这是一个可以启发思维的实例
实例位置:光盘\mingrisoft\05\156
实例说明
编程实现求一个3×3矩阵主对角线之和。具体要求如下:从键盘中任意输入9个数,将由这9个数组成的3×3矩阵输出在屏幕上,并计算出主对角线之和。运行结果如图5.22所示。
图5.22 求3×3对角矩阵之和
技术要点
本实例的关键是找出主对角线上各元素有什么特点,如果存储这个3×3矩阵的二维数组的下标从1行1列开始,我们就会发现主对角线上各元素的行数与列数是相等的,得出这一结论后就很容易求出主对角线上各元素之和了。这里有一点值得注意就是数组下标从1行1列开始使用的,故在定义二维数组时要定义成a[4][4]。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h>
(3)定义变量及二维数组a[4][4]分别为基本整型。
(4)使用嵌套的for循环将输入的数据存到二维数组a中,因为主对角线上的元素行列是相等的,故对满足该条件的元素进行累加求和。
(5)主要程序代码如下:
main() { int a[4][4], i, j, sum = 0; printf("please input numbers:\n"); for(i = 1; i <= 3; i++) for(j = 1; j <= 3; j++) scanf("%d",&a[i][j]); /*从键盘中输入9个数到二维数组a*/ printf("\nThis 3*3 matrix is:\n"); for(i = 1; i <= 3; i++) { for(j = 1; j <= 3; j++) printf("%4d",a[i][j]); /*将3*3矩阵输出*/ printf("\n"); /*每输出一行进行换行*/ } for(i = 1; i <= 3; i++) for(j = 1; j <= 3; j++) if(i==j) /*如果函数等于列数,这说明是主对角线上的元素*/ sum+=a[i][j]; /*对主对角线上的元素累加求和*/ printf("diagonal's sum is %d",sum); /*将最终结果输出*/ }
举一反三
根据本实例,读者可以:
求任意一个3×3矩阵的副对角线之和。
求任意一个4×4矩阵的对角线(包括主对角线和副对角线)之和。
实例157 矩阵的加法运算
这是一个可以提高分析能力的实例
实例位置:光盘\mingrisoft\05\157
实例说明
编程实现两个矩阵间的加法运算。具体要求如下:从键盘中分别输入两个3×3的矩阵a和矩阵b,求这两个矩阵的和这里记为c,将矩阵c显示到屏幕上。运行结果如图5.23所示。
图5.23 矩阵的加法运算
技术要点
如果矩阵a和b分别是3行3列的,那么它们相加所得到的和即矩阵c也将是3行3列的,设a、b、c3个矩阵的第i行第j列元素分别为aij、bij、cij,则cij的计算公式为:
cij=aij+bij,
i=1,2,3,j=1,2,3
将上述计算公式中的i、j换成二维数组中的行列,便可编程实现求两个矩阵相加。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h>
(3)定义变量及二维数组a、b、c分别为基本整型。
(4)使用嵌套的for循环将输入的数据分别存到二维数组a中及b中,根据技术要点中提到的公式进行加法运算,最终将矩阵c输出。
(5)主要程序代码如下:
main() { int a[3][3], b[3][3], c[3][3], i, j; printf("please input matrix a:\n"); for(i = 0; i <= 2; i++) for(j = 0; j <= 2; j++) scanf("%d",&a[i][j]); /*从键盘中输入3*3的矩阵存入数组a中*/ printf("please input matrix b:\n"); for(i = 0; i <= 2; i++) for(j = 0; j <= 2; j++) scanf("%d",&b[i][j]); /*从键盘中输入3*3的矩阵存入数组b中*/ for(i = 0; i <= 2; i++) for(j = 0; j <= 2; j++) c[i][j]=a[i][j]+b[i][j]; /*矩阵a和矩阵b中对应元素进行相加,和放入c中*/ printf("the sum is:\n"); for(i = 0; i <= 2; i++) { for(j = 0; j <= 2; j++) printf("%3d",c[i][j]); /*输出矩阵c*/ printf("\n"); /*每输出一行进行换行*/ } }
举一反三
根据本实例,读者可以:
编程实现两个矩阵间的减法运算。
编程实现求任意一个矩阵的秩。
实例158 矩阵的乘法运算
这是一个可以提高分析能力的实例
实例位置:光盘\mingrisoft\05\158
实例说明
编程实现两个矩阵间的乘法运算。具体要求如下:从键盘中分别输入一个2×3的矩阵a和一个3×2的矩阵b,求这两个矩阵的积这里记为 c,将矩阵 c 显示到屏幕上。运行结果如图5.24所示。
图5.24 矩阵的乘法运算
技术要点
如果矩阵a和b分别是2行3列和3行2列的,那么它们相乘所得到的积即矩阵c将是2行2列的,设cik是矩阵c中i行k列的元素,aij和bjk(j=1,2,3,i=1,2,k=1,2)分别表示矩阵a第i行第j列元素和矩阵b第j行第k列元素,那么就有cik=ai1*b1k+ai2*b2k+ai3*b3k
将上述计算公式中的i,j,k换成二维数组中的行列,便可编程实现求两个矩阵相乘。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h>
(3)定义变量及二维数组a、b、c分别为基本整型。
(4)使用嵌套的for循环将输入的数据分别存到二维数组a中及b中,根据技术要点中提到的公式进行乘法运算,最终将矩阵c输出。
(5)主要程序代码如下:
main() { int a[2][3], b[3][2], c[2][2], i, j, i1, sum; printf("please input martrix a:\n"); for(i = 0; i <= 1; i++) for(j = 0; j <= 2; j++) scanf("%d",&a[i][j]); /*输入2×3矩阵到数组a中*/ printf("please input martrix b;\n"); for(i = 0; i <= 2; i++) for(j = 0; j <= 1; j++) scanf("%d",&b[i][j]); /*输入3×2矩阵到数组b中*/ for(i=0;i<=1;i++) /*a矩阵的行数*/ for(k=0;k<=1;k++) /*b矩阵的列数*/ { sum = 0; for(j = 0; j <= 2; j++) sum += a[i][j] *b[j][k]; c[i][k]=sum; /*每次求得的和放入指定的行列中*/ } printf("the product is:\n"); for(i = 0; i <= 1; i++) { for(j = 0; j <= 1; j++) printf("%4d",c[i][j]); /*将矩阵c输出*/ printf("\n"); /*每输出一行进行换行*/ } }
举一反三
根据本实例,读者可以:
编程实现两个复矩阵相乘。
编程实现一般实矩阵求逆。
实例159 巧排螺旋方阵
这是一个可以提高分析能力的实例
实例位置:光盘\mingrisoft\05\159
实例说明
从键盘中任意输入一个数n(n≤10),在屏幕中打印出n阶螺旋方阵,运行结果如图5.25所示。
图5.25 n阶螺旋方阵
技术要点
输出螺旋方阵时,具体的输出过程并不难,但是在将数据往数组存储的过程中,要注意存储的顺序,即上->左->下->右,因为程序中始终是将变量k的值向数组中存储,若不注意顺序输出时便会产生错误。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h>
(3)定义变量及二维数组a分别为基本整型。
(4)使用嵌套的for循环将变量k的值分别存入每圈中相对的上面a[i][j]、右面a[j][n-i-1]、下面a[n - i -1][j]及左面a[j][i],最终将二维数组正常输出便可以得到螺旋方阵。
(5)主要程序代码如下:
main() { int i, j, k = 0, a[10][10], m, n; printf("please input n:\n"); scanf("%d", &n); if(n % 2==0) /*判断是否为偶数*/ m = n / 2; else m = n / 2+1; for(i = 0; i < m; i++) { for(j = i; j < n - i; j++) { k++; a[i][j]=k; /*将每圈中上面的行中的数据存入数组中*/ } for(j = i + 1; j < n - i; j++) { k++; a[j][n-i-1]=k; /*将每圈中右面的列中的数据存入数组中*/ } for(j = n - i -2; j >= i; j--) { k++; a[n-i-1][j]=k; /*将每圈中下面行中的数据存入数组中*/ } for(j = n - i -2; j >= i + 1; j--) { k++; a[j][i]=k; /*将每圈中左面的列中的数据存入数组中*/ } } for(i = 0; i < n; i++) { for(j = 0; j < n; j++) printf("%5d",a[i][j]); /*将螺旋矩阵输出*/ printf("\n"); /*每输出一行进行换行操作*/ } }
举一反三
根据本实例,读者可以:
要求沿逆时针方向打印题中的螺旋方阵。
要求由里向外打印该螺旋方阵,即相对实例中的图新输出的方阵中1在64的位置,64在1的位置,其他数据位置的变化依次类推。
5.5 生活中的数学
在日常生活中遇到的许多问题都需要用数学的方法来解决,在解决这些数学问题时同样可以用编程的方法来实现,用编程的方法来解决生活中的数学问题,可以将运算过程体现得更加具体而且使运算结果更加准确。
实例160 求车运行速度
本实例是一个人性化的实例
实例位置:光盘\mingrisoft\05\160
实例说明
一辆以固定速度行驶的汽车,司机在上午8点看到里程表上的读数是一个对称数(即这个数从左向右读和从右向左读是完全一样的),为95859。两小时后里程表上出现了一个新的对称数。问该车的速度是多少?新的对称数是多少?运行结果如图5.26所示。
图5.26 求车运行的速度
技术要点
本实例的关键是如何将探测到的五位数的各位分解存到数组中,方法有很多种,这里我们用到了while循环来实现该功能,举具体数字说明一下:如果i=95886,当k=100000 时,a[1]=95886%100000/10000,此时a[1]中存放的数字是9,k通过k/=10被重新赋值为10000,第二次循环a[2]=95886%10000/1000,此时a[2]中存放的是5,以此类推,a[3]、a[4]、a[5]中存放的分别是8、8、6,这样就可以通过比较第一位和第五位、第二位和第四位是否相同来判断该数字是否是我们要找的对称数。
注意:当找到对称数时,要break跳出循环,否则程序将无限循环下去。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include<stdio.h>
(3)程序中使用嵌套的while循环,外层循环的作用是从95860开始的整数进行探测直到找到对称数为止,内层循环的作用是将探测到的五位数逐位分解存到数组a中。
(4)主要程序代码如下:
main() { int j=0,a[5]; /*数组a存放分解的数字位*/ long k=100000,i=95860; /*因为95860是五位数故k=100000*/ while(1) { j=0;/*j为数组下标*/ k=100000; while(k>=10) { a[j]=(i%k)/(k/10); /*从高到低分解i值的每位数存到数组中*/ k/=10; j++; } if((a[0]==a[4])&&(a[1]==a[3])) /*比较第一位和第五位、第二位和第四位是否相同*/ { printf("The new number kelometers is:%d%d%d%d%d\n", a[0],a[1],a[2],a[3],a[4]); /*输出新的对称数*/ printf("an average speed is:%.2f\n",(i-95859)/2.0);/*将求出的平均速度输出*/ break; } i++; } }
举一反三
根据本实例,读者可以:
编程求两个大整数相加。
货物1000吨,3辆车同时起运,大车装5吨,来回一趟2小时,中车装3吨,来回一趟1.8小时(十进制),小车装2吨,来回一趟1.6小时(十进制),并规定:若有多辆车同时到达,装车的优先次序是:大车->中车->小车。不记装车时间。试编程求出最后一趟车是哪种车?大、中、小车各运多少趟?
实例161 卖西瓜
本实例是一个人性化的实例
实例位置:光盘\mingrisoft\05\161
实例说明
一农户在集市上卖西瓜,他总共有1020个西瓜,第一天卖掉一半多两个,第二天卖掉剩下的一半多两个,问照此规律买下去,该农户几天能将所有的西瓜买完,请编程实现。运行结果如图5.27所示。
图5.27 卖西瓜
技术要点
本实例设x1为西瓜的总数,每天西瓜的总数都按同一规律变化,即前一天西瓜数的一半再减2,用while循环来实现每天的变化,那么循环结束条件是什么呢?这里采用西瓜的总数作为循环结束的条件,当西瓜总数为0时,循环结束。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include<stdio.h>
(3)程序中使用while循环来实现每天西瓜数和天数的变化,x2起中间变量的作用。
(4)主函数程序代码如下:
main() { int day, x1, x2; day=0; /*天数*/ x1=1020; /*瓜的总数量*/ while(x1) { x2=x1/2-2; /*卖出一半多两个*/ x1 = x2; day++; /*天数加1*/ } printf("day=%d\n",day); /*将天数加1*/ }
举一反三
根据本实例,读者可以编程实现以下问题:
小明与小刚分别从A与B两地相对出发,经过2小时两人相遇,已知A、B两地相距7800,已知小明每小时比小刚多走1000米,编程求小刚与小明的速度。
小明搬砖,已知这堆砖共有1093块,小明每天扔掉一块砖搬走剩余砖数的三分之二,问小明在第几天再想搬砖时发现仅剩1块砖。
实例162 打渔晒网
本实例是一个人性化的实例
实例位置:光盘\mingrisoft\05\162
实例说明
如果一个渔夫从2000年1月1日开始每三天打一次鱼两天晒一次网,编程实现当输入2000年1月1日以后的任意一天,输出该渔夫是在打渔还是在晒网?运行结果如图5.28所示。
图5.28 打渔晒网问题
技术要点
要实现本实例要求的功能主要有以下两个技术要点。
第一,判断输入的年份(2000年以后包括2000年)是否是闰年,这里我们自定义函数leap来进行判断。该函数的核心内容就是闰年的判断条件即能被4整除但不能被100整除,或能被400整除。
第二,如何求输入日期距2000年1月1日有多少天。首先是判断2000年距输入的年份间有多少年,这其中有多少年是闰年就加多少个366有多少年是平年也同样加多少个365,其次是要将12个月每月的天数存到数组中,因为闰年2月份的天数有别于平年,故采用两个数组a和b分别存储。当输入年份是平年,月份为 m 的时侯就在前面累加的日期的基础上继续累加存储着平年每月天数的数组的前m-1个元素,将累加的结果加上输入的日期便求出了最终结果,闰年的算法类似。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h>
(3)自定义leap()函数,用来判断输入的年份是否是闰年,代码如下:
int leap(int a) /*自定义函数leap用来指定年份是否为闰年*/ { if(a % 4==0&&a % 100!=0||a % 400==0)/*闰年判定条件*/ return 1; /*不是闰年返回1*/ else return 0; /*不是闰年返回0*/ }
(4)自定义number()函数,用来计算输入日期距2000年1月1日共有多少天,代码如下:
int number(int year,int m,int d) /*自定义函数number计算输入日期距2000年1月1日共有多少天*/ { int sum = 0, i, j, k, a[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; /*数组a存放平年每月的天数*/ int b[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; /*数组b存放闰年每月的天数*/ if(leap(year)==1) /*判断是否为闰年*/ for(i = 0; i < m -1; i++) sum+=b[i]; /*是闰年,累加数组b前m-1个月份天数*/ else for(i = 0; i < m -1; i++) sum+=a[i]; /*不是闰年,累加数组a钱m-1个月份天数*/ for(j = 2000; j < year; j++) if(leap(j)= = 1) sum+=366; /*2000年到输入的年份是闰年的加366*/ else sum+=365; /*2000年到输入的年份不是闰年的加365*/ sum+=d; /*将前面累加的结果加上日期,求出总天数*/ return sum; /*将计算的天数返回*/ }
(5)main()函数作为程序的入口函数,代码如下:
main() { int year, month, day, n; printf("please input year,month,day\n"); scanf("%d%d%d",&year,&month,&day); /*输入年月日*/ n=number(year,month,day); /*调用函数number*/ if((n%5)<4&&(n%5)>0) /*当余数是1或2或3时说明在打渔否则在晒网*/ printf("%d:%d:%d is fishing\n", year, month, day); else printf("%d:%d:%d is basking\n", year, month, day); }
举一反三
根据本实例,读者可以编程实现以下问题:
如果一个渔夫从1990年1月1日开始每三天打一次鱼两天晒一次网,编程实现当输入1990年1月1日以后的任意一天,输出该渔夫是在打渔还是在晒网?
编程实现输入1990年后的某一年,输出该年的日历。
实例163 水池注水
本实例是一个人性化的实例
实例位置:光盘\mingrisoft\05\163
实例说明
有4个水渠(A、B、C、D)向一个水池注水,如果单开A,3天可以注满,如果单开B,1天可以注满,如果单开c,4天可以注满,如果单开D,5天可以注满。问如果A、B、C、D4 个水池同时注水,注满水池需要几天?运行结果如图5.29所示。
图5.29 水池注水问题
技术要点
首先要求出一天每渠的注水量,这里分别是1/3、1/1、1/4、1/5,要四渠共同注水就求出每天注水之和即1/3+1/1+1/4+1/5,那么1池水多久能注满只需用1除以它们的和便可。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件stdio.h:
#include<stdio.h>
(3)定义变量类型为单精度型,计算出四渠每天注水量之和,再用1除以四渠每天,就可求出多久注满一池水。
(4)主要程序代码如下:
main() { float a1=3,b1=1,c1=4,d1=5; /*定义变量为单精度型*/ float day; /*定义天数为单精度型*/ day = 1 /(1 / a1 + 1 / b1 + 1 / c1 + 1 / d1); /*计算四渠同时注水多久可以注满*/ printf("need %f day!",day); /*将计算出的天数输出*/ }
举一反三
根据本实例,读者可以:
在本实例基础上编程计算如果只开A和B两个水渠进行注水,多久可以把水池注满?
在本实例基础上编程计算如果只开C和D两个水渠进行注水,多久可以把水池注满?
实例164 捕鱼和分鱼
本实例是一个人性化的实例
实例位置:光盘\mingrisoft\05\164
实例说明
A、B、C、D、E五个人在某天夜里合伙去捕鱼,到第二天凌晨时都疲惫不堪,于是各自找地方睡觉。第二天,A第一个醒来,他将鱼分成五份,把多余的一条鱼扔掉,拿走自己的一份。B第二个醒来,也将鱼分为五份,把多余的一条扔掉,拿走自己的一份,C、D、E依次醒来,也按同样的方法拿鱼。问他们合伙至少捕了多少条鱼?程序运行结果如图5.30所示。
图5.30 捕鱼和分鱼问题
技术要点
根据题意假设鱼的总数是x,那么第一次每人分到的鱼的数量可用(x-1)/5表示,余下的鱼数为4×(x-1)/5,将余下的数量重新赋值给x,依然调用(x-1)/5,如果连续五次x-1后均能被5整除,则说明最初的x值便是本题目的解。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h>
(3)假定sum的范围为100~10000,依照技术要点中讲的方法对这些数字进行筛选,对满足条件的将其输出并退出程序。
(4)main()函数作为程序的入口函数,代码如下:
main() { int sum,i,j,n=0; /*定义变量为基本整型*/ for(sum = 100; sum < 10000; sum++) { j = sum; n = 0; while((j-1)% 5==0) /*如果j-1能被5整除,则执行循环体语句*/ { n++; /*n起计数作用*/ if(n==5) /*当n=5时说明sum值即为所求结果*/ { printf("the total number of fish is %d",sum);/*将sum输出*/ exit(0); } else j=(j-1)*4/5; /*每次剩余的鱼的数量*/ } } }
举一反三
根据本实例,读者可以编程实现以下问题:
请用乘方函数解决本实例。
输入5个1~9之间的数字,在屏幕上输出由这5个数字构成的一个正确的乘法等式。
实例165 递归解分鱼
本实例是一个人性化的实例
实例位置:光盘\mingrisoft\05\165
实例说明
A、B、C、D、E五个人在某天夜里合伙去捕鱼,到第二天凌晨时都疲惫不堪,于是各自找地方睡觉。第二天,A第一个醒来,他将鱼分成五份,把多余的一条鱼扔掉,拿走自己的一份。B第二个醒来,也将鱼分为五份,把多余的一条扔掉,拿走自己的一份,C、D、E依次醒来,也按同样的方法拿鱼。问他们合伙至少捕了多少条鱼?程序运行结果如图5.31所示。
图5.31 捕鱼和分鱼问题
技术要点
本实例采用了递归的方法来求解鱼的总数,这里有一点需要强调,用递归求解时一定要注意要有递归结束的条件。本实例中n=1时便是递归程序的出口。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h>
(3)自定义fish()函数,用递归实现求鱼的总数,代码如下:
int fish(int n) /*定义函数递归求鱼的总数*/ { if(n==1) /*当n等于1时递归结束*/ { static int i = 0; do { i++; } while(i % 5 != 0); return(i+1); /*5人平分后多出一条*/ } else { int t; do { t = fish(n -1); } while(t % 4 != 0); return(t / 4 * 5+1) ; } }
(4)main()函数作为程序的入口函数,代码如下:
main() { int total; total=fish(5); /*调用递归函数*/ printf("the total number of fish is %d\n",total); }
举一反三
根据本实例,读者可以:
用递归的方法解决四塔问题。
用换位递归的方法解决汉诺塔问题。
实例166 巧分苹果
这是一个可以启发思维的实例
实例位置:光盘\mingrisoft\05\166
实例说明
一家农户以果园为生,一天,父亲推出一车苹果,共2520个,准备分给他的6个儿子。父亲先按事先写在一张纸上的数字把这堆苹果分完,每个人分到的苹果的个数都不相同。然后他说:“老大,把你分到的苹果分1/8给老二,老二拿到后,连同原来的苹果分1/7给老三,老三拿到后,连同原来的苹果分1/6给老四,依此类推,最后老六拿到后,连同原来的苹果分1/3给老大,这样,你们每个人分到的的苹果就一样多了。”问兄弟6人原先各分到多少只苹果?程序运行结果如图5.32所示。
图5.32 巧分苹果
技术要点
要解决本实例首先要分析其中的规律,这里我们设xi(i=1、2、3、4、5、6)依次为6个兄弟原来分到的苹果数,设yi=(2、3、4、5、6)为出老大外其余5个兄弟从哥哥那里得到还未分给弟弟时的苹果数,那么老大是个特例则x1=y1。因为苹果的总数是2520,那么我们可以很容易便知道6个人平均每人得到的苹果数s应为420,则可得到如下关系:
y2=x2+(1/8)*y1,
y2*(6/7)=s;
y3=x3+(1/7)*y2,
y3*(5/6)=s;
y4=x4+(1/6)*y3,
y4*(4/5)=s;
y5=x5+(1/5)*y4,
y5*(3/4)=s;
y6=x6+(1/4)*y5,
y6*(2/3)=s;
以上求s都是有规律的,对于老大的求法这里单列,即y1=x1,x1*(7/8)+y6*(1/3)=s;
根据上面分析的内容,我们利用数组便可实现巧分苹果。
实现过程
(1)在TC中创建一个C文件。
(2)引用头文件:
#include <stdio.h>
(3)利用循环和数组先求出从哥哥得到分来的苹果却未分给弟弟时的数目,在该数的基础上再求原来每人分到的苹果数。
(4)main()函数作为程序的入口函数,代码如下:
main() { int x[7], y[7], s, i; s=2520/6; /*求出平均每个人要分多少个苹果*/ for(i = 2; i <= 6; i++) /*求从老二到老六得到哥哥分来的苹果却未分给弟弟时的苹果数*/ y[i] = s *(9-i)/(8-i); y[1] = x[1] =(s - y[6] / 3)*8 / 7; /*老大得到老六分来的苹果却未分给弟弟时的苹果数*/ for(i = 2; i <= 6; i++) x[i]=y[i]-y[i-1]/(10-i); /*求原来每人得到的苹果数*/ for(i = 1; i <= 6; i++) printf("x[%d]=%d\n",i,x[i]); /*将最终结果输出*/ }
举一反三
根据本实例,读者可以:
编程解决灯塔问题。
用数组解决凉东问题。