谁是赢家谁先走教学设计.这样公平吗

查看: 438|回复: 17
美媒称中国科技创新赶超西方:“中国创造”引关注
参考消息网6月13日报道 美媒称,上周在上海举办的亚洲消费电子展有助于展示来自中国的技术创新门类。从机器人、无人机、自动驾驶、虚拟现实到精巧的电子产品,来自中国科技巨头的全部产品都在展出之列。
据美国《福布斯》双周刊网站6月11日报道,有意思的是,同样类型的科技在今年早些时候拉斯维加斯举办的消费电子展也备受关注。这是第三届亚洲消费电子展,每次都在上海举行。
报道称,对参加中国展会的新来者而言,很可能会意外地发现中国的科技创新与西方同步。在某些领域,中国甚至领先于西方,比如移动互联网领域的支付、电子商务以及信息传递。
不同国家的技术领导者确实各有不同。在中国,所有的创新都是以百度、阿里巴巴和腾讯为核心。在美国,它围绕着亚马逊、谷歌、脸书及其他公司。很少有美国科技公司能够渗透到中国市场。人们记忆之中的仅有微软、领英网、爱彼迎及一些汽车制造商。
报道称,随着中国为本土市场研发自己的创新产品,它正从中国制造向中国创造过渡。这一趋势正在受到世界越来越多的关注。
这里的秘诀是市场规模及潜力、保护政策。实际上,中国政府早在20年前就开始在互联网领域施行中国优先政策,比特朗普提出美国优先策略早多了。
在互联网领域施行中国优先策略,有其客观基础:1、政府统治的需要;2、上面提到的市场规模及潜力;3、保护产生新产业;4、分享利润(就是到美国股市上市)。
类比一下美国制造业和基础设施领域施行美国优先的基础:
1、政策执行力有限;2、制造业市场过剩以及基础设施投资利润率低下;3、保护维持旧产业;4、可以做到分享利润,但未必有想象空间。
特朗普的美国优先政策在制造业和基础设施建设领域可能取得进展,但最好降低期望值。
赶英超美,全民创业,万众创新
在中国,所有的创新都是以百度、阿里巴巴和腾讯为核心。在美国,它围绕着亚马逊、谷歌、脸书及其他公司。很少有美国科技公司能够渗透到中国市场。人们记忆之中的仅有微软、领英网、爱彼迎及一些汽车制造商。
==============================================
人家Google在搞人工智能,百度在搞外卖,跟莆田游医搞到一起;
腾讯整个就是个山寨公司,靠山寨别人的产品生存;
淘宝的假货,呵呵,地球人都知道。
在中国,所有的创新都是以百度、阿里巴巴和腾讯为核心。在美国,它围绕着亚马逊、谷歌、脸书及其他公司。很 ...
你这个观念比外国人都落后了
科技进步会带来海量的失业
科技进步会带来海量的失业
那是结构性的失业,毕竟利益无法均衡分配---------------------但总体看,在电商腾飞的近十年,俺国就业情况还可以。
目前看,美中两个互联网超级大国的就业形势比其他大国要好,这似乎说明新兴产业科技领先的国家,创造就业的能力比那些新兴产业科技落伍的国家要强。
那是结构性的失业,毕竟利益无法均衡分配---------------------但总体看,在电商腾飞的近十年,俺国就业 ...
摆地摊的去摆网摊了
摆地摊的去摆网摊了
摆地摊还可行,摆网摊估计95%的不挣钱。
摆地摊还可行,摆网摊估计95%的不挣钱。
在他们消耗掉积蓄后,才会变成无产阶级
在他们消耗掉积蓄后,才会变成无产阶级
他们哪里来的那么多积蓄啊????
我觉得专职开网店的应该不多,大部分应该是兼职开网店,主要收入应该不靠网店,靠网店的只能是极少数幸运优胜者。
你这个观念比外国人都落后了
欧洲观念是全面落后,中国是COPY美国。
欧洲成为本轮危机的泄洪区吗
欧洲观念是全面落后,中国是COPY美国。
中国也不是全拷贝美国,阿里巴巴模式就是独创的。
欧洲成为本轮危机的泄洪区吗
现在已经走出危机了,不过,估计下一次危机已经悄悄临近了。
中国也不是全拷贝美国,阿里巴巴模式就是独创的。
B2C是COPY美国的,然后才有的B2B,整个电子商务的概念就是从美国传过来的。
B2C是COPY美国的,然后才有的B2B,整个电子商务的概念就是从美国传过来的。
那是总体概念,我说的是阿里集团的独特模式创新。
Powered by当前位置: >>
100个经典C语言程序
经典 C 语言程序 1.绘制余弦曲线 在屏幕上用“*”显示 0~360 度的余弦函数 cos(x)曲线 *问题分析与算法设计 如果在程序中使用数组,这个问题十分简单。但若规定不能使用数组,问题就变得不容易了。 关键在于余弦曲线在 0~360 度的区间内,一行中要显示两个点,而对一般的显示器来说,只能按行输出, 即:输出第一行信息后,只能向下一行输出,不能再返回到上一行。为了获得本文要求的图形就必须在一 行中一次输出两个“*” 。 为了同时得到余弦函数 cos(x)图形在一行上的两个点,考虑利用 cos(x)的左右对称性。将屏幕的行方向定 义为 x,列方向定义为 y,则 0~180 度的图形与 180~360 度的图形是左右对称的,若定义图形的总宽度为 6 2 列,计算出 x 行 0~180 度时 y 点的坐标 m,那么在同一行与之对称的 180~360 度的 y 点的坐标就 应为 6 2-m。程序中利用反余弦函数 acos 计算坐标(x,y)的对应关系。 使用这种方法编出的程序短小精炼,体现了一定的技巧。 *程序说明与注释 #include&stdio.h& #include&math.h& void main() { int x,m; for(y=1;y&=-1;y-=0.1) { m=acos(y)*10; printf(&*&); printf(&*\n&); } } 2.绘制余弦曲线和直线 在屏幕上显示 0~360 度的 cos(x)曲线与直线 f(x)=45*(y-1)+31 的迭加图形。 其中 cos(x)图形用“*”表示, f(x) 用“+”表示,在两个图形相交的点上则用 f(x)图形的符号。 *问题分析与算法设计 本题可以在上题的基础上进行修改。图形迭加的关键是要在分别计算出同一行中两个图形的列方向点坐 标后,正确判断相互的位置关系。为此,可以先判断图形的交点,再分别控制打印两个不同的图形。 *程序注释与说明 #include&stdio.h& #include&math.h& void main() { int x,m,n, for(yy=0;yy&=20;yy++) /*对于第一个 y 坐标进行计算并在一行中打印图形*/ /*计算出 y 对应的弧度 m,乘以 10 为图形放大倍数*/ /*控制打印左侧的 * 号*/ /*控制打印同一行中对称的右侧*号*/ for(x=1;x&m;x++) printf(& &); for(;x&62-m;x++)printf(& &); /*y 为列方向,值从 1 到-1,步长为 0.1*/ { y=0.1* m=acos(1-y)*10; n=45*(y-1)+31; for(x=0;x&=62;x++) else if(x==n) printf(&+&); else printf(& &); printf(&\n&); } } 3.绘制圆 在屏幕上用“*”画一个空心的圆 *问题分析与算法设计 打印圆可利用图形的左右对称性。根据圆的方程: R*R=X*X+Y*Y 可以算出圆上每一点行和列的对应关系。 *程序说明与注释 #include&stdio.h& #include&math.h& void main() { int x,m; for(y=10;y&=-10;y--) { m=2.5*sqrt(100-y*y); /*计算行 y 对应的列坐标 m,2.5 是屏幕纵横比调节系数因为屏幕的 /*图形左侧空白控制*/ /*图形的空心部分控制*/ 行距大于列距,不进行调节显示出来的将是椭圆*/ for(x=1;x&30-m;x++) printf(& &); printf(&*&); printf(&*\n&); } } 4.歌星大奖赛 在歌星大奖赛中,有 10 个评委为参赛的选手打分,分数为 1~100 分。选手最后得分为:去掉一个最高分 和一个最低分后其余 8 个分数的平均值。请编写一个程序实现。 *问题分析与算法实现 这个问题的算法十分简单,但是要注意在程序中判断最大、最小值的变量是如何赋值的。 *程序说明与注释 #include&stdio.h& void main() for(;x&30+m;x++) printf(& &); /*圆的左侧*/ /*圆的右侧*/ /*y:屏幕行方向坐标*/ /*m: cos(x)曲线上 y 点对应的屏幕列坐标*/ /*n: 直线上 y 点对应的列坐标*/ /*x: 屏幕列方向坐标*/ /*打印不相交时的直线图形*/ /*其它情况打印空格*/if(x==m&&x==n) printf(&+&); /*直线与 cos(x)相交时打印“+”*/ else if(x==m||x==62-m) printf(&*&); /*打印不相交时的 cos(x)图形*/ { int integer,i,max,min, max=-32768; min=32767; sum=0; for(i=1;i&=10;i++) { printf(&Input number %d=&,i); scanf(&%d&,&integer); sum+= /*输入评委的评分*/ /*计算总分*/ /*通过比较筛选出其中的最高分*/ /*通过比较筛选出其中的最低分*/ /*先假设当前的最大值 max 为 C 语言整型数的最小值*/ /*先假设当前的最小值 min 为 C 语言整型数的最大值*/ /*将求累加和变量的初值置为 0*/if(integer&max)max= if(integer&min)min= }printf(&Canceled max score:%d\nCanceled min score:%d\n&,max,min); printf(&Average score:%d\n&,(sum-max-min)/8); } *运行结果 Input number1=90 Input number2=91 Input number3=93 Input number4=94 Input number5=90 Input number6=99 Input number7=97 Input number8=92 Input number9=91 Input number10=95 Canceled max score:99 Canceled min score:90 Average score:92 *思考题 题目条件不变,但考虑同时对评委评分进行裁判,即在 10 个评委中找出最公平(即评分最接返平均分)和 最不公平(即与平均分的差距最大)的评委,程序应该怎样实现? 5.求最大数 问 555555 的约数中最大的三位数是多少? *问题分析与算法设计 根据约数的定义,对于一个整数 N,除去 1 和它自身外,凡能整除 N 的数即为 N 的约数。因此,最简单 的方法是用 2 到 N-1 之间的所有数去除 N,即可求出 N 的全部约数。本题只要求取约数中最大的三位数, 则其取值范围可限制在 100 到 999 之间。 *程序说明与注释 #include&stdio.h& void main() { /*输出结果*/
printf(&Please input number:&); scanf(&%ld&,&i); for(j=999;j&=100;j--) if(i%j==0) { printf(&The max factor with 3 digits in %ld is:%d,\n&,i,j); } } *运行结果 输入:555555 输出:The max factor with 3 digits in 555555 is:777 6.高次方数的尾数 求 13 的 13 次方的最后三位数 *问题分析与算法设计 解本题最直接的方法是:将 13 累乘 13 次方截取最后三位即可。 但是由于计算机所能表示的整数范围有限,用这种“正确”的算法不可能得到正确的结果。事实上,题 目仅要求最后三位的值,完全没有必要求 13 的 13 次方的完整结果。 研究乘法的规律发现:乘积的最后三位的值只与乘数和被乘数的后三位有关,与乘数和被乘数的高位无 关。利用这一规律,可以大大简化程序。 *程序说明与注释 #include&stdio.h& void main() { int i,x,y,last=1; /*变量 last 保存求 X 的 Y 次方过程中的部分乘积的后三位*/ printf(&Input X and Y(X**Y):&); scanf(&%d**%d&,&x,&y); for(i=1;i&=y;i++) last=last*x%1000; } *运行结果 Input X and Y(X**Y):13**13 The last 3 digits of 13**13 is:253 Input X and Y(X**Y):13**20 The last 3 digits of 13**20 is:801 8.借书方案知多少 小明有五本新书,要借给 A,B,C 三位小朋友,若每人每次只能借一本,则可以有多少种不同的借法? *问题分析与算法设计 本问题实际上是一个排列问题,即求从 5 个中取 3 个进行排列的方法的总数。首先对五本书从 1 至 5 进 行编号,然后使用穷举的方法。假设三个人分别借这五本书中的一本,当三个人所借的书的编号都不相同 /*X 自乘 Y 次*/ /*将 last 乘 X 后对 1000 取模,即求积的后三位*/printf(&The last 3 digits of %d**%d is:%d\n&,x,y,last%1000); /*打印结果*/ 时,就是满足题意的一种借阅方法。 *程序说明与注释 void main() { int a,b,c,count=0; printf(&There are diffrent methods for XM to distribute books to 3 readers:\n&); for(a=1;a&=5;a++) for(b=1;b&=5;b++) /*穷举第一个人借 5 本书中的 1 本的全部情况*/ /*穷举第二个人借 5 本书中的一本的全部情况*/ /*当前两个人借不同的书时,穷举第三个人借 5 本书 中的 1 本的全部情况*/ if(c!=a&&c!=b) /*判断第三人与前两个人借的书是否不同*/ printf(count%8?&%2d:%d,%d,%d &:&%2d:%d,%d,%d\n &,++count,a,b,c); /*打印可能的借阅方法*/ } *运行结果 There are diffrent methods for XM to distribute books to 3 readers: 1: 1,2,3 6: 1,3,5 11:1,5,3 16:2,3,1 21:2,4,5 26:3,1,4 31:3,4,1 36:3,5,4 41:4,2,3 46:4,5,1 51:5,1,4 56:5,3,2 9.杨辉三角形 在屏幕上显示杨辉三角形 1 1 1 1 1 1 5 4 10 3 6 10 2 3 4 5 1 1 1 1 1 2: 1,2,4 7: 1,4,2 12:1,5,4 17:2,3,4 22:2,5,1 27:3,1,5 32:3,4,2 37:4,1,2 42:4,2,5 47:4,5,2 52:5,2,1 57:5,3,4 3: 1,2,5 8: 1,4,3 13:2,1,3 18:2,3,5 23:2,5,3 28:3,2,1 33:3,4,5 38:4,1,3 43:4,3,1 48:4,5,3 53:5,2,3 58:5,4,1 4: 1,3,2 9: 1,4,5 14:2,1,4 19:2,4,1 24:2,5,4 29:3,2,4 34:3,5,1 39:4,1,5 44:4,3,2 49:5,1,2 54:5,2,4 59:5,4,2 5: 1,3,4 10:1,5,2 15:2,1,5 20:2,4,3 25:3,1,2 30:3,2,5 35:3,5,2 40:4,2,1 45:4,3,5 50:5,1,3 55:5,3,1 60:5,4,3for(c=1;a!=b&&c&=5;c++)...................................... *问题分析与算法设计 杨辉三角形中的数, 正是(x+y)的 N 次方幂展开式各项的系数。 本题作为程序设计中具有代表性的题目, 求解的方法很多,这里仅给出一种。 从杨辉三角形的特点出发,可以总结出: 1)第 N 行有 N+1 个值(设起始行为第 0 行) 2)对于第 N 行的第 J 个值:(N&=2) 当 J=1 或 J=N+1 时:其值为 1 J!=1 且 J!=N+1 时:其值为第 N-1 行的第 J-1 个值与第 N-1 行第 J 个值之和 将这些特点提炼成数学公式可表示为: 1 c(x,y)= c(x-1,y-1)+c(x-1,y) 其它 x=1 或 x=N+1本程序应是根据以上递归的数学表达式编制的。 *程序说明与注释 #include&stdio.h& void main() { int i,j,n=13; printf(&N=&); while(n&12) scanf(&%d&,&n); for(i=0;i&=n;i++) { for(j-0;j&24-2*i;j++) printf(& &); printf(&\n&); } } void int c(int x,int y) { if((y==1)||(y==x+1)) z=c(x-1,y-1)+c(x-1,y); } return 1; /*若为 x 行的第 1 或第 x+1 列,则输出 1*/ /*否则,其值为前一行中第 y-1 列与第 y 列值之和*/ /*求杨辉三角形中第 x 行第 y 列的值*/ /*控制输出第 i 行前面的空格*/ /*输出第 i 行的第 j 个值*/ for(j=1;j&i+2;j++) printf(&%4d&,c(i,j)); /*控制输入正确的值以保证屏幕显示的图形正确*/ /*控制输出 N 行*/10.数制转换 将任一整数转换为二进制形式 *问题分析与算法设计 将十进制整数转换为二进制的方法很多,这里介绍的实现方法利用了 C 语言能够对位进行操作的特点。 对于 C 语言来说,一个整数在计算机内就是以二进制的形式存储的,所以没有必要再将一个整数经过一系 列的运算转换为二进制形式,只要将整数在内存中的二进制表示输出即可。 *程序说明与注释 #include&stdio.h& void printb(int,int); void main() { printf(&Input number:&); scanf(&%d&,&x); printf(&number of decimal form:%d\n&,x); printf(& it's binary form:&); sizeof(int)*8:int 型对应的位数*/ putchar('\n'); } void printb(int x,int n) { if(n&0) { putchar('0'+((unsigned)(x&(1&&(n-1)))&&(n-1))); printb(x,n-1); } } *运行结果 输入:8 输出: number of decimal form:8 it's bunary form:1000 输入:-8 输出:number of decimal form:-8 it's binary form:1000 输入:32767 输出:number of decimal form:32767 it's binary form:1111 输入:-32768 输出:number of decimal form:-32768 it's binary form:0000 输入:128 输出:number of decimal form:128 it's binary form:0000 11.打鱼还是晒网 中国有句俗语叫“三天打鱼两天晒网”。某人从 1990 年 1 月 1 日起开始“三天打鱼两天晒网”,问这 个人在以后的某一天中是“打鱼”还是“晒网”。 *问题分析与算法设计 根据题意可以将解题过程分为三步: 1)计算从 1990 年 1 月 1 日开始至指定日期共有多少天; 2)由于“打鱼”和“晒网”的周期为 5 天,所以将计算出的天数用 5 去除; 3)根据余数判断他是在“打鱼”还是在“晒网”; 若 否则 余数为 1,2,3,则他是在“打鱼” 是在“晒网” /*归调用,输出 x 的后 n-1 位*/ /*输出第 n 位*/ printb(x,sizeof(int)*8); /*x:整数 sizeof(int):int 型在内存中所占的字节数 在这三步中,关键是第一步。求从 1990 年 1 月 1 日至指定日期有多少天,要判断经历年份中是否有闰 年,二月为 29 天,平年为 28 天。闰年的方法可以用伪语句描述如下: 如果 ((年能被 4 除尽 且 不能被 100 除尽)或 能被 400 除尽) 则 否则 *程序与程序注释 #include&stdio.h& int days(struct date day); struct date{ }; void main() { struct date today, int yearday,year, printf(&Enter year/month/day:&); scanf(&%d%d%d&,&today.year,&today.month,&today.day); term.month=12; term.day=31; { term.year= yearday+=days(term); } yearday+=days(today); day=yearday%5; /*加上指定年中到指定日期的天数*/ /*求余数*/ /*打印结果*/ /*计算从 1990 年至指定年的前一年共有多少天*/ /*设置变量的初始值:月*/ /*设置变量的初始值:日*/ /*输入日期*/ 该年是闰年; 不是闰年。C 语言中判断能否整除可以使用求余运算(即求模)for(yearday=0,year=1990;year&today.year++)if(day&0&&day&4) printf(&he was fishing at that day.\n&); else printf(&He was sleeping at that day.\n&); } int days(struct date day) { static int day_tab[2][13]= {{0,31,28,31,30,31,30,31,31,30,31,30,31,}, {0,31,29,31,30,31,30,31,31,30,31,30,31,}, }; int i, lp=day.year%4==0&&day.year%100!=0||day.year%400==0; /*判定 year 为闰年还是平年,lp=0 为平年,非 0 为闰年*/ for(i=1;i&day.i++) day.day+=day_tab[lp];/*平均每月的天数*//*计算本年中自 1 月 1 日起的天数*/ return day. } *运行结果 Enter year/month/day: He was fishing at day. Enter year/month/day: He was sleeping at day. Enter year/month/day: He was sleeping at day12.抓交通肇事犯 一辆卡车违反交通规则,撞人后逃跑。现场有三人目击事件,但都没有记住车号,只记下车号的一些特 征。甲说:牌照的前两位数字是相同的;乙说:牌照的后两位数字是相同的,但与前两位不同; 丙是数学 家,他说:四位的车号刚好是一个整数的平方。请根据以上线索求出车号。 *问题分析与算法设计 按照题目的要求造出一个前两位数相同、后两位数相同且相互间又不同的整数,然后判断该整数是否是 另一个整数的平方。 *程序与程序注释 #include&stdio.h& #include&math.h& void main() { int i,j,k,c; for(i=1;i&=9;i++) for(j=0;j&=9;j++) if(i!=j) { k=i*1000+i*100+j*10+j; /*计算出可能的整数*/ for(c=31;c*c&k;c++); /*判断该数是否为另一整数的平方*/ /*若是,打印结果*/ if(c*c==k) printf(&Lorry--No. is %d.\n&,k); } } *运行结果 Lorry _No.is 7744 13.该存多少钱 假设银行一年整存零取的月息为 0.63%。现在某人手中有一笔钱,他打算在今后的五年中的年底取出 1 000 元,到第五年时刚好取完,请算出他存钱时应存入多少。 *问题分析与算法设计 分析存钱和取钱的过程,可以采用倒推的方法。若第五年年底连本带息要取 1000 元,则要先求出第五 年年初银行存款的钱数: 第五年初存款=*0.0063) 依次类推可以求出第四年、第三年......的年初银行存款的钱数: /*i:车号前二位的取值*/ /*j:车号后二位的取值*/ /*判断二位数字是否相异*/ 第四年年初存款=(第五年年初存款+1000)/(1+12*0.0063) 第三年年初存款=(第四年年初存款+1000)/(1+12*0.0063) 第二年年初存款=(第三年年初存款+1000)/(1+12*0.0063) 第一年年初存款=(第二年年初存款+1000)/(1+12*0.0063) 通过以上过程就可以很容易地求出第一年年初要存入多少钱。 *程序与程序注释 #include&stdio.h& void main() { float total=0; for(i=0;i&5;i++) total=(total+1000)/(1+0.0063*12); /*i 为年数,取值为 0~4 年*/ /*累计算出年初存款数额,第五次的计算 结果即为题解*/ printf(&He must save %.2f at first.\n&,total); } *运行结果 He must save 4039.44 at first 14.怎样存钱利最大 假设银行整存整取存款不同期限的月息利率分别为: 0.63% 0.66% 0.69% 0.75% 0.84% 期限=1 年 期限=2 年 期限=3 年 期限=5 年 期限=8 年利息=本金*月息利率*12*存款年限。 现在某人手中有 2000 元钱, 请通过计算选择一种存钱方案, 使得钱存入银行 20 年后得到的利息最多(假 定银行对超过存款期限的那一部分时间不付利息)。 *问题分析与算法 为了得到最多的利息,存入银行的钱应在到期时马上取出来,然后立刻将原来的本金和利息加起来再 作为新的本金存入银行, 这样不断地滚动直到满 20 年为止, 由于存款的利率不同, 所以不同的存款方法(年 限)存 20 年得到的利息是不一样的。 分析题意,设 2000 元存 20 年,其中 1 年存 i1 次,2 年存 i2 次,3 年存 i3 次,5 年存 i5 次,8 年存 i8 次,则到期时存款人应得到的本利合计为: 2000*(1+rate1)i1*(1+rate2)i2*(1+rate3)i3*(1+rate5)i5*(1+rate8)i8 其中 rateN 为对应存款年限的利率。根据题意还可得到以下限制条件: 0&=i8&=2 0&=i5&=(20-8*i8)/5 0&=i3&=(20-8*i8-5*i5)/3 0&=i2&=(20-8*i8-5*i5-3*i3)/2 0&=i1=20-8*i8-5*i5-3*i3-2*i2 可以用穷举法穷举所有的 i8、i5、i3、i2 和 i1 的组合,代入求本利的公式计算出最大值,就是最佳 存款方案。 *程序与程序注释 #include&stdio.h& #include&math.h& void main() { int i8,i5,i3,i2,i1,n8,n5,n3,n2,n1; float max=0, for(i8=0;i8&3;i8++) /*穷举所有可能的存款方式*/ for(i5=0;i5&=(20-8*i8)/5;i5++) for(i3=0;i3&=(20-8*i8-5*i5)/3;i3++) for(i2=0;i2&=(20-8*i8-5*i5-3*i3)/2;i2++) { i1=20-8*i8-5*i5-3*i3-2*i2; term=2000.0*pow((double)(1+0.0063*12),(double)i1) *pow((double)(1+2*0.0063*12),(double)i2) *pow((double)(1+3*0.0069*12),(double)i3) *pow((double)(1+5*0.0075*12),(double)i5) *pow((double)(1+8*0.0084*12),(double)i8); /*计算到期时的本利合计*/ if(term&max) { max=n1=i1;n2=i2;n3=i3;n5=i5;n8=i8; } } printf(&For maxinum profit,he should so save his money in a bank:\n&); printf(& printf(& printf(& printf(& printf(& printf(& } *运行结果 For maxinum profit,he should so save his money in a bank: made fixed deposit for 8 year: 0times made fixed deposit for 5 year: 4times made fixed deposit for 3 year: 0times made fixed deposit for 2 year: 0times made fixed deposit for 1 year: 0times Total:8841.01 可见最佳的存款方案为连续四次存 5 年期。 made fixed deposit for 8 year: %d times\n&,n8); made fixed deposit for 5 year: %d times\n&,n5); made fixed deposit for 3 year: %d times\n&,n3); made fixed deposit for 2 year: %d times\n&,n2); made fixed deposit for 1 year: %d times\n&,n1); Toal: %.2f\n&,max); /*输出存款方式*/*思考题 某单位对职工出售住房,每套为 2 万元。买房付款的方法是: 一次交清,优惠 20% 从第一年开始,每年年初分期付款: 5 年交清,优惠 50%; 10 年交清,优惠 10%; 20 年交清,没有优惠。 现在有人手中正好有 2 万元,若假定在今后 20 年中物价和银行利率均保持不变,问他应当选择哪种付 款方式可以使应付的钱最少?15.捕鱼和分鱼 A、B、C、D、E 五个人在某天夜里合伙去捕鱼,到第二天凌晨时都疲惫不堪,于是各自找地方睡觉。日 上三杆,A 第一个醒来,他将鱼分为五份,把多余的一条鱼扔掉,拿走自己的一份。B 第二个醒来,也将 鱼分为五份,把多余的一条鱼扔掉,保持走自己的一份。C、D、E 依次醒来,也按同样的方法拿走鱼。问 他们合伙至少捕了多少条鱼? *问题分析与算法设计 根据题意,总计将所有的鱼进行了五次平均分配,每次分配时的策略是相同的,即扔掉一条鱼后剩下的 鱼正好分成五份,然后拿走自己的一份,余下其它的四份。 假定鱼的总数为 X,则 X 可以按照题目的要求进行五次分配:X-1 后可被 5 整除,余下的鱼为 4*(X-1)、 5。若 X 满足上述要求,则 X 就是题目的解。 *程序与程序注释 #include&stdio.h& void main() { int n,i,x,flag=1; for(n=6;n++) { for(x=n,i=1&&i&=5;i++) if((x-1)%5==0) x=4*(x-1)/5; else flag=0; if(flag) else flag=1; } printf(&Total number of fish catched=%d\n&,n); } *运行结果 Total number of fish catched = 3121 *问题的进一步讨论 程序采用试探法,试探的初值为 6,每次试探的步长为 1。这是过分保守的做法。可以在进一步分析题目 的基础上修改此值,增大试探的步长值,以减少试探次数。 *思考题 请使用其它的方法求解本题 16.出售金鱼 /*输出结果*/ /*若不能分配则置标记 falg=0 退出分配过程*/ /*若分配过程正常结束则找到结果退出试探的过程*/ /*否则继续试探下一个数*/ /*flag:控制标记*/ /*采用试探的方法。令试探值 n 逐步加大*/ 买卖提将养的一缸金鱼分五次出售系统上一次卖出全部的一半加二分之一条;第二次卖出余下的三分之 一加三分之一条;第三次卖出余下的四分之一加四分之一条;第四次卖出余下的五分之一加五分之一条; 最后卖出余下的 11 条。问原来的鱼缸中共有几条金鱼? *题目分析与算法设计 题目中所有的鱼是分五次出售的,每次卖出的策略相同;第 j 次卖剩下的(j+1)分之一再加 1/(j+1)条。第 五次将第四次余下的 11 条全卖了。 假定第 j 次鱼的总数为 X,则第 j 次留下: x-(x+1)/(j+1) 当第四次出售完毕时,应该剩下 11 条。若 X 满足上述要求,则 X 就是题目的解。 应当注意的是:&(x+1)/(j+1)&应满足整除条件。试探 X 的初值可以从 23 开始,试探的步长为 2,因为 X 的值一定为奇数。 *程序说明与注释 #include&stdio.h& void main() { int i,j,n=0,x; for(i=23;n==0;i+=2) { for(j=1,x=i;j&=4&&x&=11;j++) /*完成出售四次的操作*/ if((x+1)%(j+1)==0) x-=(x+1)/(j+1); else {x=0;} if(j==5&&x==11) { printf(&There are %d fishes at first.\n&,i); n=1; } } } *运行结果 There are 59 fishes at first. *思考题 日本著名数学游戏专家中村义作教授提出这样一个问题:父亲将 2520 个桔子分给六个儿子。分完后父 亲说:“老大将分给你的桔子的 1/8 给老二;老二拿到后连同原先的桔子分 1/7 给老三;老三拿到后连同 原先的桔子分 1/6 给老四;老四拿到后连同原先的桔子分 1/5 给老五;老五拿到后连同原先的桔子分 1/4 给老六;老六拿到后连同原先的桔子分 1/3 给老大”。结果大家手中的桔子正好一样多。问六兄弟原来手 中各有多少桔子? 1.7 分数四则运算 对输入的两个分数进行+、-、*、/四则运算,输出分数结果。 算法分析如下: 对分数 b/a 与 d/c,不管哪一种运算,其运算结果均为 y/x 形式。对结果 y/x 进行化简,约去分子分 母的公因数:试用 i(i=1,...,y)对 y,x 进行试商,若能同时整除 y,x,则 y,x 同时约去公因数 i,最后打 印约简的分数。 /*输出结果*/ /*控制退出试探过程*/ /*否则停止计算过程*/ /*若第四次余下 11 条则满足题意*/ /*若满足整除条件则进行实际的出售操作*/ /*n 为标志变量*/ /*控制试探的步长和过程*/ 程序代码如下: #include&stdio.h& void main() { long int a,b,c,d,i,x,y,z; printf(&两分数 b/a,d/c 作+,-,*,/四则运算,结果为分数。\n&); printf(&请输入分数运算式。\n&); scanf(&%ld/%ld%c%ld/%ld&,&b,&a,&op,&d,&c); if(a==0||c==0) {printf(&分母为 0 输入错误!&);exit(0);} if(op=='+'){y=b*c+d*a;x=a*c;} if(op=='-'){y=b*c-d*a,x=a*c;} if(op=='*'){y=b*d;x=a*c;} if(op=='/'){y=b/c;x=a/d;} z=x; if(x&y) z=y; i=z; while(i&1) { if(x%i==0&&y%i==0){x=x/i;y=y/i;} i--; } printf(&%ld/%ld%c%ld/%ld=%ld/%ld.\n&,b,a,op,d,c,y,x); } /*y/x 分子分母约去公因数*/ /*运算结果均为 y/x*/17.平分七筐鱼 甲、乙、丙三位鱼夫出海打鱼,他们随船带了 21 只箩筐。当晚返航时,他们发现有七筐装满了鱼,还有 七筐装了半筐鱼,另外七筐则是空的,由于他们没有秤,只好通过目测认为七个满筐鱼的重量是相等的,7 个半筐鱼的重量是相等的。在不将鱼倒出来的前提下,怎样将鱼和筐平分为三份? *问题分析与算法设计 根据题意可以知道:每个人应分得七个箩筐,其中有 3.5 筐鱼。采用一个 3*3 的数组 a 来表示三个人分 到的东西。其中每个人对应数组 a 的一行,数组的第 0 列放分到的鱼的整筐数,数组的第 1 列放分到的半 筐数,数组的第 2 列放分到的空筐数。由题目可以推出: 。数组的每行或每列的元素之和都为 7; 。对数组的行来说,满筐数加半筐数=3.5; 。每个人所得的满筐数不能超过 3 筐; 。每个人都必须至少有 1 个半筐,且半筐数一定为奇数 对于找到的某种分鱼方案,三个人谁拿哪一份都是相同的,为了避免出现重复的分配方案,可以规定: 第二个人的满筐数等于第一个人的满筐数;第二个人的半筐数大于等于第一个人的半筐数。 *程序与程序注释 #include&stdio.h& int a[3][3], void main() { int i,j,k,m,n, printf(&It exists possible distribtion plans:\n&); for(i=0;i&=3;i++) { a[0][0]=i; for(j=i;j&=7-i&&j&=3;j++) { a[1][0]=j; if((a[2][0]=7-j-a[0][0])&3) if(a[2][0]&a[1][0]) for(k=1;k&=5;k+=2) { a[0][1]=k; for(m=1;m&7-k;m+=2) { a[1][1]=m; a[2][1]=7-k-m; for(flag=1,n=0;flag&&n&3;n++) /*判断每个人分到的鱼是 3.5 筐,flag 为满足题意的标记变量*/ if(a[n][0]+a[n][1]&7&&a[n][0]*2+a[n][1]==7) a[n][2]=7-a[n][0]-a[n][1]; else flag=0; if(flag) { printf(&No.%d for(n=0;n&3;n++) printf(& } } } } } } * 运行结果 It exists possible distribution plans: No.1 fisher A: fisher B: fisher C: No.2 fisher A: fisher B: Full basket 1 3 3 Full basket 2 2 Semi--basket 5 1 1 3 3 1 3 3 Empty 2 2 Empty fisher %c: %d %d %d\n&, 'A'+n,a[n][0],a[n][1],a[n][2]); Full basket Semi--basket Empty\n&,++count); /*计算应得到的空筐数量*/ /*不符合题意则置标记为 0*/ /*试探 半筐 a[1][1]的值,半筐数为奇数*/ /*第三个人满筐数不能&3*/ /*要求后一个人分的满筐数&=前一个人,以排除重复情况*/ /*试探第二个人满筐 a[1][0]的值,满筐数不能&3*/ /*试探第一个人满筐 a[0][0]的值,满筐数不能&3*//*试探半筐 a[0][1]的值,半筐数为奇数*/Semi--basket fisher C: *思考题313晏会上数学家出了一道难题:假定桌子上有三瓶啤酒,癣瓶子中的酒分给几个人喝,但喝各瓶酒的人 数是不一样的。不过其中有一个人喝了每一瓶中的酒,且加起来刚好是一瓶,请问喝这三瓶酒的各有多少 人? (答案:喝三瓶酒的人数分别是 2 人、3 人和 6 人) 18.有限 5 位数 个位数为 6 且能被 3 整除的五位数共有多少? *题目分析与算法设计 根据题意可知,满足条件的五位数的选择范围是 1。。。99996。可设基础数 i=1000,通 过计算 i*10+6 即可得到欲选的数(i 的变化范围是 ),再判断该数能否被 3 整除。 *程序说明与注释 #include&stdio.h& void main() { int count=0; for(i=1000;i&9999;i++) if(!((i*10+6)%3)) count++; } *运行结果 count=2999 /*判断所选的数能否被 3 整除*/ /*若满足条件则计数*/ /*count:统计满足条件的五位数的个数*/printf(&count=%d\n&,count);*思考题 求 100 到 1000 之间有多少个其数字之和为 5 的整数。 (答案:104,113,122,131,140,203,212,221,230,302,311,320,401,410,500) 19. 8 除不尽的数 一个自然数被 8 除余 1,所得的商被 8 除也余 1,再将第二次的商被 8 除后余 7,最后得到一个商为 a。 又知这个自然数被 17 除余 4,所得的商被 17 除余 15,最后得到一个商是 a 的 2 倍。求这个自然数。 *题目分析与算法设计 根据题意,可设最后的商为 i(i 从 0 开始取值),用逆推法可以列出关系式: (((i*8+7)*8)+1)*8+1=((2*i*17)+15)*18+4 再用试探法求出商 i 的值。 *程序说明与注释 #include&stdio.h& void main() { for(i=0;;i++) /*试探商的值*/ if(((i*8+7)*8+1)*8+1==(34*i+15)*17+4) {/*逆推判断所取得的当前 i 值是否满足关系式*/ /*若满足则输出结果*/ printf(&The required number is: %d\n&,(34*i+15)*17+4); /*退出循环*/} } *运行结果 The required number is:199320.一个奇异的三位数 一个自然数的七进制表达式是一个三位数,而这个自然数的九进制表示也是一个三位数,且这两个三 位数的数码正好相反,求这个三位数。 *题目分析与算法设计 根据题意可知, 七进制和九进制表示的这全自然数的每一位一定小于 7, 可设其七进制数形式为 kji(i、 j、k 的取值分别为 1~6),然后设其九进制表示形式为 ijk。 *程序说明与注释 #include&stdio.h& void main() { int i,j,k; for(i=1;i&7;i++) for(j=0;j&7;j++) for(k=1;k&7;k++) if(i*9*9+j*9+k==i+j*7+k*7*7) { printf(&The special number with 3 digits is:&); printf(&%d%d%d(7)=%d%d%d(9)=%d(10)\n&,k,j,i,i,j,k,i*9*9+j*9+k); } } *运行结果 The special number with 3 digits is:503(7)=305(9)=248(10)21.4 位反序数 设 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。 *程序说明与注释 #include&stdio.h& void main() { for(i=1002;i&1111;i++)/*穷举四位数可能的值*/if(i%10*1000+i/10%10*100+i/100%10*10+i/1000==i*9) /*判断反序数是否是原整数的 9 倍*/ printf(&The number satisfied stats condition is: %d\n&,i); /*若是则输出*/ } *运行结果 The number satisfied states condition is:1089 22.求车速 一辆以固定速度行驶的汽车,司机在上午 10 点看到里程表上的读数是一个对称数(即这个数从左向右读 和从右向左读是完全一样的), 为 95859。 两小时后里程表上出现了一个新的对称数。 问该车的速度是多少? 新的对称数是多少? *题目分析与算法设计 根据题意,设所求对称数为 i,其初值为 95589,对其依次递增取值,将 i 值的每一位分解后与其对称位 置上的数进行比较,若每个对称位置上的数皆相等,则可判定 i 即为所求的对称数。 *程序说明与注释 #include&stdio.h& void main() { int t,a[5]; long int k,i; for(i=95860;;i++) { for(t=0,k=100000;k&=10;t++) { a[t]=(i%k)/(k/10); k/=10; } if((a[0]==a[4])&&(a[1]==a[3])) { printf(&The new symmetrical number kelometers is:%d%d%d%d%d\n&, a[0],a[1],a[2],a[3],a[4]); printf(&The velocity of the car is: %.2f\n&,(i-9); } } } *运行结果 The new symmetrical number kelometers is:95959. The velocity of the car is:50.00 *思考题 将一个数的数码倒过来所得到的新数叫原数的反序数。如果一个数等于它的反序数,则称它为对称数。 求不超过 1993 的最大的二进制的对称数 /*从高到低分解所取 i 值的每位数*/ /* 字,依次存放于 a[0]~a[5]中*/ /*以 95860 为初值,循环试探*/ /*数组 a 存放分解的数字位*/ 23.阿姆斯特朗数 如果一个正整数等于其各个数字的立方和,则称该数为阿姆斯特朗数(亦称为自恋性数)。 如 407=43+03+73 就是一个阿姆斯特朗数。试编程求 1000 以内的所有阿姆斯特朗数。 *题目分析与算法设计 可采用穷举法,依次取 1000 以内的各数(设为 i),将 i 的各位数字分解后,据阿姆斯特朗数的性质进 行计算和判断。 *程序说明与注释 #include&stdio.h& void main() { int i,t,k,a[3]; printf(&There are follwing Armstrong number smaller than 1000:\n&); for(i=2;i&1000;i++) { for(t=0,k=1000;k&=10;t++) { a[t]=(i%k)/(k/10); k/=10; } if(a[0]*a[0]*a[0]+a[1]*a[1]*a[1]+a[2]*a[2]*a[2]==i) /*判断 i 是否为阿姆斯特朗数*/ printf(&%5d&,i); } printf(&\n&); } *运行结果 There are following Armstrong number smaller than 0 371 407 /*若满足条件,则输出*/ /*分别赋于 a[0]~a[2}*/ /*截取整数 i 的各位(从高向低位)*/ /*穷举要判定的数 i 的取值范围 2~1000*/24.完全数 如果一个数恰好等于它的因子之和,则称该数为“完全数” 。 *题目分析与算法设计 根据完全数的定义,先计算所选取的整数 a(a 的取值 1~1000)的因子,将各因子累加于 m,若 m 等于 a, 则可确认 a 为完全数。 *程序说明与注释 #include&stdio.h& void main() { int a,i,m; printf(&There are following perfect numbers smaller than 1000:\n&); for(a=1;a&1000;a++) { /*循环控制选取 1~1000 中的各数进行判断*/ for(m=0,i=1;i&=a/2;i++) if(!(a%i))m+=i; if(m==a) printf(&%4d } printf(&\n&); } *运行结果 &,a);/*计算 a 的因子,并将各因子之和 m=a,则 a 是完全数输出*/TThere are following perfect numbers smaller than
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 的因子。 *程序说明与注释 #include&stdio.h& void main() { int a,i,b,n; printf(&There are following friendly--numbers pair smaller than 3000:\n&); for(a=1;a&3000;a++) { for(b=0,i=1;i&=a/2;i++) if(!(a%i))b+=i; if(!(b%i))n+=i; if(n==a&&a&b) printf(&%4d..%4d } } *运行结果 There are following friendly--numbers pair smaller than .. 284 27.自守数 自守数是指一个数的平方的尾数等于该数自身的自然数。例如: 252=625 762== 请求出 200000 以内的自守数 *题目分析与算法设计 若采用“求出一个数的平方后再截取最后相应位数”的方法显然是不可取的,因为计算机无法表示过大 的整数。 分析手工方式下整数平方(乘法)的计算过程,以 376 为例: 1184.. .. 2924 &,a,b); /*若 n=a,则 a 和 b 是一对亲密数,输出*/ for(n=0,i=1;i&=b/2;i++) /*计算数 a 的各因子,各因子之和存放于 b*/ /*计算 b 的各因子,各因子之和存于 n*/ /*穷举 1000 以内的全部整数*/ 376 X 376 ---------28 ---------141376被乘数 乘数 第一个部分积=被乘数*乘数的倒数第一位 第二个部分积=被乘数*乘数的倒数第二位 第三个部分积=被乘数*乘数的倒数第三位 积本问题所关心的是积的最后三位。分析产生积的后三位的过程,可以看出,在每一次的部分积中,并不 是它的每一位都会对积的后三位产生影响。总结规律可以得到:在三位数乘法中,对积的后三位产生影响 的部分积分别为: 第一个部分积中:被乘数最后三位*乘数的倒数第一位 第二个部分积中:被乘数最后二位*乘数的倒数第二位 第三个部分积中:被乘数最后一位*乘数的倒数第三位 将以上的部分积的后三位求和后截取后三位就是三位数乘积的后三位。这样的规律可以推广到同样问题 的不同位数乘积。 按照手工计算的过程可以设计算法编写程序。 *程序说明与注释 #include&stdio.h& void main() { long mul,number,k,ll, printf(&It exists following automorphic nmbers small than 200000:\n&); for(number=0;number&200000;number++) { for(mul=number,k=1;(mul/=10)&0;k*=10); /*由 number 的位数确定截取数字进行乘法时的系数 k*/ kk=k*10; mul=0; ll=10; { mul=(mul+(number%(k*10))*(number%ll-number%(ll/10)))% /*(部分积+截取被乘数的后 N 位*截取乘数的第 M 位),%kk 再截取部分积*/ k/=10; ll*=10; } if(number==mul) printf(&%ld } } *运行结果 It exsts following automorphic numbners smaller than
1 5 6 25 76 376 625
109376 /*判断若为自守数则输出*/ &,number); /*k 为截取被乘数时的系数*/ while(k&0) /*kk 为截取部分积时的系数*/ /*积的最后 n 位*/ /*ll 为截取乘数相应位时的系数*/ 28.回文数 打印所有不超过 n(取 n&256) 的其平方具有对称性质的数(也称回文数)。 *题目分析与算法设计 对于要判断的数 n,计算出其平方后(存于 a),将 a 的每一位进行分解,再按 a 的从低到高的顺序将其恢 复成一个数 k(如 n=13,则 a=169 且 k=961),若 a 等于 k 则可判定 n 为回亠数。 *程序说明与注释 #include&stdio.h& void main() { int m[16],n,i,t,count=0; long unsigned a,k; printf(&No. { k=0;t=1;a=n*n; for(i=1;a!=0;i++) { m=a%10; a/=10; } for(;i&1;i--) { k+=m[i-1]*t; t*=10; } if(k==n*n) printf(&%2d%10d%10d\n&,++count,n,n*n); } } *运行结果 No. 1 2 3 4 5 6 7 8 9 number 1 2 3 11 22 26 101 111 121 it's square(palindrome) 1 4 9 121 484 676
14641 /*计算 n 的平方*/ /*从低到高分解数 a 的每一位存于数组 m[1]~m[16]*/ number it's square(palindrome)\n&); /*穷举 n 的取值范围*/ for(n=1;n&256;n++)29.求具有 abcd=(ab+cd)2 性质的四位数 3025 这个数具有一种独特的性质:将它平分为二段,即 30 和 25,使之相加后求平方,即(30+25)2,恰 好等于 3025 本身。请求出具有这样性质的全部四位数。 *题目分析与算法设计 具有这种性质的四位数没有分布规律,可以采用穷举法,对所有四位数进行判断,从而筛选出符合这种 性质的四位数。具体算法实现,可任取一个四位数,将其截为两部分,前两位为 a,后两位为 b,然后套用 公式计算并判断。 *程序说明与注释 #include&stdio.h& void main() { int n,a,b; printf(&There are following number with 4 digits satisfied condition\n&); for(n=1000;n&10000;n++) { a=n/100; b=n%100; if((a+b)*(a+b)==n) printf(&%d &,n); } } *运行结果 There are following numbers with 4 digits satisfied condition: 2025 30.求素数 求素数表中 1~1000 之间的所有素数 *问题分析与算法设计 素数就是仅能衩 1 和它自身整除的整数。判定一个整数 n 是否为素数就是要判定整数 n 能否被除 1 和它 自身之外的任意整数整除,若都不能整除,则 n 为素数。 程序设计时 i 可以从 2 开始,到该整数 n 的 1/2 为止,用 i 依次去除需要判定的整数,只要存在可以整除 该数的情况,即可确定要判断的整数不是素数,否则是素数。 *程序与程序注释 #include&stdio.h& void main() { int n1,nm,i,j,flag,count=0; do{ printf(&Input START and END=?&); scanf(&%d%d&,&n1,&nm); }while(!(n1&0&&n1&nm)); if(n1==1||n1==2) { printf(&%4d&,2); n1=3;count++; } /*输入求素数的范围*/ /*输入正确的范围*/ /*处理素数 2*/
/*截取 N 的前两位数存于 a*/ /*截取 N 的后两位存于 b*/ /*判断 N 是否为符合题目所规定的性质的四位数*/ /*四位数 N 的取值范围 */printf(&...........PRIME TABLE(%d--%d)............\n&,n1,nm); for(i=n1;i&=i++) { if(!(i%2))/*判定指定范围内的整数是否为素数*/for(flag=1,j=3;flag&&j&i/2;j+=2) /*判定能否被从 3 到整数的一半中的某一数所整除*/ if(!(i%j))flag=0; } } 31.歌德巴赫猜想 验证:2000 以内的正偶数都能够分解为两个素数之和(即验证歌德巴赫猜想对 2000 以内的正偶数成立)。 *问题分析与算法设计 为了验证歌德巴赫猜想对 2000 以内的正偶数都是成立的,要将整数分解为两部分,然后判断出分解出的 两个整数是否均为素数。若是,则满足题意;否则重新进行分解和判断。 程序中对判断是否为素数的算法进行了改进, 对整数判断 “用从 2 开始到该整数的一半”改为“2 开始到该 整数的平方根” 。原因何在请自行分析。 *程序与程序注释 #include&stdio.h& #include&math.h& int fflag(int n); void main() { int i,n; for(i=4;i&=2000;i+=2) { for(n=2;n&i;n++) if(fflag(n)) if(fflag(i-n)) { printf(&%14d=%d+%d\n&,i,n,i-n); } if(n==i) printf(&error %d\n&,i); } } int fflag(int i) { if(i&=1)return 0; if(i==2)return 1; if(!(i%2))return 0; if(!(i%j))return 0; /*if no,return 0*/ for(j=3;j&=(int)(sqrt((double)i)+1);j+=2) /*判断是否为素数*/ /*若均是素数则输出*/ /*将偶数 i 分解为两个整数*/ /*分别判断两个整数是否均为素数*/ /*若能整除则不是素数*/ if(flag) printf(++count%15?&%4d&:&%4d\n&,i); return 1; } 32.要发就发/*if yes,return 1*/“1898--要发就发” 。请将不超过 1993 的所有素数从小到大排成第一行,第二行上的每个素数都等于它右 肩上的素数之差。编程求出:第二行数中是否存在这样的若干个连续的整数,它们的和恰好是 1898?假好 存在的话,又有几种这样的情况? 第一行:2 3 5 7 11 13 17......93 第二行:1 2 2 4 2 4...... *问题分析与算法设计: 首先从数学上分析该问题: 假设第一行中的素数为 n[1]、n[2]、n[3]....n、...第二行中的差值为 m[1] 、m[2]、m[3]...m[j]...。其中 m[j] 8 6为:m[j]=n[j+1]-n[j] 。则第二行连续 N 个数的和为:SUM=m[1]+m[2]+m[3]+...+m[j] =(n[2]-n[1])+(n[3]-n[2])+(n[4]-n[3])+...+(n[j+1]-n[j]) =n[j+1]-n[1]由此题目就变成了:在不超过 1993 的所有素数中是否存在这样两个素数,它们的差恰好是 1898。若存在, 则第二行中必有所需整数序列,其和恰为 1898, 。 对等价问题的求解是比较简单的。 由分析可知,在素数序列中不必包含 2,因为任意素数与 2 的差一定为奇数,所以不必考虑。*程序与程序注释: #include&stdio.h& #include&math.h& #define NUM 320 int number[NUM]; int fflag(int i); void main() { int i,j,count=0; printf(&there are follwing primes sequences in first row:\n&); for(j=0,i=3;i&=1993;i+=2) if(fflag(i)) number[j++]=i; for(j--;number[j]&1898;j--) { for(i=0;number[j]-number&1898;i++); /*循环查找满足条件的素数*/ if(number[j]-number==1898) } } /*若两个素数的差为 1898,则输出*/ printf(&(%d).%3d,.....,%d\n&,++count,number,number[j]); /*从最大的素数开始向 1898 搜索*/ /*求出不超过 1993 的全部奇数*/ /*存放不超过 1993 的全部奇数*/int fflag(int i) { if(i&=1) return 0; if(i==2) return 1; if(!(i%2)) return 0; if(!(i%j)) return 0; return 1; } *运行结果/*判断是否为素数*/ /*if no, return 0*/for(j=3;j&=(int)(sqrt((double)i)+1);j+=2)There are follwing primes sequences in first row: (1).89,......,,......,1951 (3). 3,......,1901*思考题 将 1,2,3,。。。,20 这 20 个连续的自然数排成一圈,使任意两个相邻的自然数之和均为素数。 35.素数幻方 求四阶的素数幻方。即在一个 4X4 的矩阵中,每一个格填 入一个数字,使每一行、每一列和两条对 角线上的 4 个数字所组成的四位数,均为可逆素数。 *问题分析与算法设计 有了前面的基础,本题应当说是不困难的。 最简单的算法是:采用穷举法,设定 4X4 矩阵中每一个元素的值后,判断每一行、每一列和两条对角 线上的 4 个数字组成的四位数是否都是可逆素数,若是则求出了满足题意的一个解。 这种算法在原理是对的,也一定可以求出满足题意的全部解。但是,按照这一思路编出的程序效率很 低,在微机上几个小时也不会运行结束。这一算法致命的缺陷是:要穷举和判断的情况过多。 充分利用题目中的“每一个四位数都是可逆素数”这一条件,可以放弃对矩阵中每个元素进行的穷举 的算法,先求出全部的四位可逆素数(204 个),以矩阵的行为单位,在四位可逆素数的范围内进行穷举, 然后将穷举的四位整数分解为数字后,再进行列和对角线方向的条件判断,改进的算法与最初的算法相比, 大大地减少了穷举的次数。 考虑矩阵的第一行和最后一行数字,它们分别是列方向四位数的第一个数字和最后一个数字,由于这 些四位数也必须是可逆素数,所以矩阵的每一行和最后一行中的各个数字都不能为偶数或 5。这样穷举矩 阵的第一行和最后一行时,它们的取值范围是:所有位的数字均不是偶数或 5 的四位可逆数。由于符合这 一条件的四位可逆素数很少,所以这一范围限制又一次减少了穷举的次数。 对算法的进一步研究会发现:当设定了第一和第二行的值后,就已经可以判断出当前的这种组合是否 一定是错误的(尚不能肯定该组合一定是正确的)。若按列方向上的四个两位数与四位可逆数的前两位矛盾 (不是其中的一种组合),则第一、二行的取值一定是错误的。同理在设定了前三行数据后,可以立刻判断 出当前的这种组合是否一定是错误的,若判断出矛盾情况,则可以立刻设置新的一组数据。这样就可以避 免将四个数据全部设定好以后再进行判断所造成的低效。 根据以上分析,可以用伪语言描述以上改进的算法: 开始 找出全部四位的可逆素数; 确定全部出现在第一和最后一行的四位可逆素数; 在指定范围 内穷举第一行 在指定范围内穷举第二行 若第一、第二、三行已出现矛盾,则继续穷举下一个数; 在指定范围内穷举第四行 判断列和对角方向是否符合题意 若符合题意,则输出矩阵; 否则继续穷举下一个数; 结束 在实际编程中,采用了很多程序设计技巧,假如设置若干辅助数组,其目的就是要最大限度的提高程 序的执行效率,缩短运行时间。下面的程序运行效率是比较高的。 *程序与程序注释 #include&stdio.h& #include&math.h& int number[210][5]; int select[110]; int array[4][5]; int larray[2][200]; int lcount[2]; int num(int number); int ok(int number); void process(int i); void copy_num(int i); int comp_num(int n); int find1(int i); int find2(void); int find0(int num); void p_array(void); void main() { int i,k,flag,cc=0,i1,i4; printf(&there are magic squares with invertable primes as follw:\n&); for(i=1001;i&9999;i+=2) { k=i/1000; if(k%2!=0&&k!=5&&num(i)) { number[count][0]=i; process(count++); /*存入数组*/ /*分解素数的各位数字*/ /*若可逆素数满足放在矩阵第一行*/ /*和最后一行的条件,记录可逆素数的*/ /*下标,计数器加 1*/ /*若可逆素数的第一位不是偶数或 5*/ /*求满足条件的可逆素数*/ /*存放可逆素数及素数分解后的各位数字*/ /*可以放在矩阵第一行和最后一行的素数的下标*/ /*4X4 的矩阵,每行 0 号元素存可逆素数对应的数组下标*/ /*可逆素数的数目*/ /*可以放在矩阵第一行和最后一行的可逆素数的数目*/ /*存放素数前二、三位数的临时数组所对应的数量计数器*/if(number[count-1][2]%2!=0&& number[count-1][3]%2!=0&& number[count-1][2]!=5&& number[count-1][3]!=5)select[selecount++]=count-1; } } larray[0][lcount[0]++]=number[0][0]/100; larray[1][lcount[1]++]=number[0][0]/10; for(i=1;i&i++) { if(larray[0][lcount[0]-1]!=number[0]/100) larray[0][lcount[0]++]=number[0]/100; if(larray[1][lcount[1]-1]!=number[0]/10) larray[1][lcount[1]++]=number[0]/10; } for(i1=0;i1&i1++) { array[0][0]=select[i1]; copy_num(0); { copy_num(1); if(!comp_num(2)) { copy_num(2); if(!comp_num(3)) { array[3][0]=select[i4]; copy_num(3); if(!find1(i))flag=0; if(flag&&find2()) } } } } } int num(int number) { if(!ok(number)) return 0; for(j=0;number&0;number/=10) /*将素数变为反序数*/ /*判断是否可逆素数*/ /*判断对角线是否为可逆素数*/ /*输出幻方矩阵*/ { printf(&No.%d\n&,++cc); p_array(); } /*复制分解的数字*/ /*判断每列是否可逆素数*/ for(flag=1,i=1;flag&&i&=4;i++) /*若每列的前三位的组成与素数相矛盾,则试探下一个数*/ /*在最后一行允许的范围内穷举*/ for(i4=0;i4&i4++) /*复制分解的数字*/ /*若每列的前两位的组成与素数相矛盾,则试探下一个数*/ /*穷举第三行*/ for(array[2][0]=0;array[2][0]&array[2][0]++) /*复制分解的数字*/ /*取对应的素数下标*/ /*复制分解的素数*/ /*穷举第二行*/ /*在第一行允许的汇聚围内穷举*/ /*临时数组的第一行存前二位*/ /*临时数组的第二行存前三位*//*将素数不重复的前二、三位存入临时数组中*/for(array[1][0]=0;array[1][0]&array[1][0]++) j=j*10+number%10; if(!ok(j)) return 0; return 1; } int ok(int number) { int i,j; if(number%2==0) return 0; j=sqrt((double)number)+1; for(i=3;i&=j;i+=2) if(number%i==0) return 0; return 1; } void process(int i) { int j, num=number[0]; for(j=4;j&=1;j--,num/=10) number[j]=num%10; } void copy_num(int i) { for(j=1;j&=4;j++) array[j]=number[array[0&[j]; } int comp_num(int n) { int i,num,k,*p; int * switch(n){ /*用内部静态变量保存前一次查找到的元素下标*/ /*ii:前一次查找前二位的下标,jj:前一次查找前三位的下标*/ /*p:指向对应的要使用的前一次下标 ii 或 jj*/ /*pcount:指向要使用的临时数组数量的计数器*/ /*根据 n 的值选择对应的一组控制变量*/ /*判断 array 中每列的前 n 位是否与可逆素数允许的前 n 位矛盾*/ /*将 array[0]指向的素数的各位数字复制到 array 中*/ /*将第 i 个整数分解为数字并存入数组*/ /*判断是否为素数*/ /*判断反序数是否为素数*/case 2:pcount=&lcount[0];p=& case 3:pcount=&lcount[1];p=& default:return 0; } for(i=1;i&=4;i++) { for(num=0,k=0;k&n;k++) num=num*10+array[k]; /*计算前 n 位数字代表的数值*/ /*对四列分别进行处理*/ if(num&=larray[n-2][*p]) else/*与前一次最后查找到的元素进行比较*/for(;*p&=0&&num&larray[n-2][*p];(*p)--);/*若前次查找到的元素大,则向前找*/ for(;p&pcount&&num&larray[n-2][*p];(*p)++); /*否则向后找*/ if(*p&0||*p&=*pcount) { *p=0; return 0; } if(num!=larray[n-2][*p]) return 0; } return 1; } int find1(int i) { int num,j; for(num=0,j=0;j&4;j++) num=num*10+array[j]; return find0(num); } int find2(void) { int num1,num2,i,j; for(num1=0,j=0;j&4;j++) num1=num1*10+array[j][j+1]; for(num2=0,j=0,i=4;j&4;j++,i--) num2=num2*10+array[j]; if(find0(num1)) return(find0(num2)); else return 0; } int find0(int num) { if(num&=number[j][0])for(;j&=0&&num&number[j][0];j--); else for(;j&count&&num&number[j][0];j++); if(j&0||j&=count){ j=0;return 0; } if(num==number[j][0]) return 1; else return 0; } void p_array(void) { /*输出矩阵*/ /*查找是否为满足要求的可逆素数*/ /*判断对角线方向是否是可逆素数*/ /*判断列方向是否是可逆素数*/ /*前 n 位不是可逆素数允许的值则返回 0*/ int i,j; for(i=0;i&4;i++) { for(j=1;j&=4;j++) printf(&%d &,array[j]); printf(&\n&); } }36.百钱百鸡问题 中国古代数学家张丘建在他的《算经》中提出了著名的“百钱买百鸡问题” :鸡翁一,值钱五,鸡母一, 值钱三,鸡雏三,值钱一,百钱买百鸡,问翁、母、雏各几何? *题目分析与算法设计 设鸡翁、鸡母、鸡雏的个数分别为 x,y,z,题意给定共 100 钱要买百鸡,若全买公鸡最多买 20 只,显然 x 的值在 0~20 之间;同理,y 的取值范围在 0~33 之间,可得到下面的不定方程: 5x+3y+z/3=100 x+y+z=100 所以此问题可归结为求这个不定方程的整数解。 由程序设计实现不定方程的求解与手工计算不同。在分析确定方程中未知数变化范围的前提下,可通过 对未知数可变范围的穷举,验证方程在什么情况下成立,从而得到相应的解。 *程序说明与注释 #include&stdio.h& void main() { int x,y,z,j=0; printf(&Folleing are possible plans to buy 100 fowls with 100 Yuan.\n&); for(x=0;x&=20;x++) for(y=0;y&=33;y++) { z=100-x-y; /*内外层循环控制下,鸡雏数 z 的值受 x,y 的值的制约 */ /*验证取 z 值的合理性及得到一组解的合理性*/ printf(&%2d:cock=%2d hen=%2d chicken=%2d\n&,++j,x,y,z); } } *运行结果 Follwing are possible plans to buy 100 fowls with 100 Yuan. 1:cock=0 hen=25 chicken=75 2:cock=4 hen=18 chicken=78 3:cock=8 hen=11 chicken=81 4:cock=12 hen=4 chicken=84 *总是的进一步讨论 这类求解不定方程总理的实现,各层循环的控制变量直接与方程未知数有关,且采用对未知数的取值范 上穷举和组合的方法来复盖可能得到的全部各组解。能否根据题意更合理的设置循环控制条件来减少这种 穷举和组合的次数,提高程序的执行效率,请读者考虑。 if(z%3==0&&5*x+3*y+z/3==100) /*外层循环控制鸡翁数*/ /*内层循环控制鸡母数 y 在 0~33 变化*/ 37.爱因斯坦的数学题 爱因斯坦出了一道这样的数学题:有一条长阶梯,若每步跨 2 阶,则最最后剩一阶,若每步跨 3 阶,则 最后剩 2 阶,若每步跨 5 阶,则最后剩 4 阶,若每步跨 6 阶则最后剩 5 阶。只有每次跨 7 阶,最后才正好 一阶不剩。请问这条阶梯共有多少阶? *题目分析与算法设计 根据题意,阶梯数满足下面一组同余式: x≡1 (mod2) x≡2 (mod3) x≡4 (mod5) x≡5 (mod6) x≡0 (mod7) *程序说明与注释 #include&stdio.h& void main() { int i=1; ++i; } *运行结果 Staris_number=119 *问题的进一步讨论 此题算法还可考虑求 1、2、4、5 的最小公倍数 n,然后判 t(t 为 n-1)≡0(mod7)是否成立,若不成立则 t=t +n,再进行判别,直至选出满足条件的 t 值。请自行编写程序实现。 39.年龄几何 张三、李四、王五、刘六的年龄成一等差数列,他们四人的年龄相加是 26,相乘是 880,求以他们的年 龄为前 4 项的等差数列的前 20 项。 *题目分析与算法设计 设数列的首项为 a,则前 4 项之和为&4*n+6*a&,前 4 项之积为&n*(n+a)*(n+a+a)*(n+a+a+a)&。同时&1&=a& =4&,&1&=n&=6&。可采用穷举法求出此数列。 *程序说明与注释 #include&stdio.h& void main() { int n,a,i; printf(&The series with equal difference are:\n&); for(n=1;n&=6;n++) for(a=1;a&=4;a++) for(i=0;i&20;i++) printf(&%d &,n+i*a); } *运行结果 /*输出前 20 项*/ /*公差 n 取值为 1~6*/ /*首项 a 取值为 1~4*/ /*i 为所设的阶梯数*/ /*满足一组同余式的判别*/ while(!((i%2==1)&&(i%3==2)&&(i%5==4)&&(i%6==5)&&(i%7==0))) printf(&Staris_number=%d\n&,i);if(4*n+6*a==26&&n*(n+a)*(n+a+a)*(n+a+a+a)==880) /*判断结果*/ The series with equal difference are: 2 5 8 11 14 17 20 23 26 29 32 35 38 41 44 47 50 53 56 59 38.换分币 用一元人民币兑换成 1 分、2 分和 5 分硬币,共有多少种不同的兑换方法。 *题目分析与算法设计 根据题意设 i,j,k 分别为兑换的 1 分、2 分、5 分硬币所具有的钱数(分),则 i,j,k 的值应满足: i+j+k=100 *程序说明与注释 #include&stdio.h& void main() { int i,j,k,count=1; printf(&There are follwing small exchange plans for 1 Yuan note:\n&); for(i=0;i&=100;i++) for(j=0;j&=100-i;j+=2) if(i+j+k==100) printf(count%4?&%d:1*%d+2*%d+5*%d\t&:&%d:1*%d+2*%d+5*%d\n&,count++,i,j/2,k/5); } 40.三色球问题 若一个口袋中放有 12 个球,其中有 3 个红的。3 个白的和 6 个\的,问从中任取 8 个共有多少种不同 的颜色搭配? *题目分析与算法设计 设任取的红球个数为 i,白球个数为 j,则\球个数为 8-i-j,根据题意红球和白球个数的取值范围是 0~3,在红球和白球个数确定的条件下,\球个数取值应为 8-i-j&=6。 *程序说明与注释 #include&stdio.h& void main() { int i,j,count=0; printf(& RED BALL WHITE BALL BLACKBALL\n&); printf(&..................................................\n&); for(i=0;i&=3;i++) for(j=0;j&=3;j++) if((8-i-j)&=6) printf(& %2d: } 41.马克思手稿中的数学题 马克思手稿中有一道趣味数学问题:有 30 个人,其中有男人、女人和小孩,在一家饭馆吃饭花了 50 先令;每个男人花 3 先令,每个女人花 2 先令,每个小孩花 1 先令;问男人、女人和小孩各有几人? *题目分析与算法设计 设 x,y,z 分别代表男人、女人和小孩。按题目的要求,可得到下面的方程: x+y+z=30 (1) %d %d %d\n&,++count,i,j,8-i-j); /*循环控制变量 i 控制任取红球个数 0 ̄3*/ /*循环控制变量 j 控制任取白球个数 0 ̄3*/ /*i 为 1 分硬币钱数,可取值 0,1,2...,100*/ /*j 为 2 分硬币钱数,可取 0 值,2,4,...,100*/ /*k 为 5 分硬币钱数*/for(k=0;k&=100-i-2*j;k+=5) 3x+2y+z=50 2x+y=20 由(3)式可知,x 变化范围是 0~10 *程序说明与注释 #include&stdio.h& void main() { int x,y,z,count=0; printf(& for(x=0;x&=10;x++) { y=20-2*x; z=30-x-y; if(3*x+2*y+z==50) printf(& %2d: } } 42.最大公约数和最小公倍数 %d Men(2) (3)用方程程序求此不定方程的非负整数解,可先通过(2)-(1)式得:WomenChildren\n&);printf(&........................................\n&);/*x 定值据(3)式求 y*/ /*由(1)式求 z*/ /*当前得到的一组解是否满足式(2)*/ %d %d\n&,++count,x,y,z);求任意两个正整数的最大公约数和(GCD)和最小公倍数(LCM) *问题分析与算法设计 手工方式求两个正整数的j大公约数的方法是用辗转相除法,在程序中可以模拟这种方式。 *程序与程序注释 #include&stdio.h& void main() { int a,b,num1,num2, printf(&Input a & b:&); scanf(&%d%d&,&num1,&num2); if(num1&num2) { temp=num1; num1=num2; num2= } a=num1; b=num2; while(b!=0) { temp=a%b; a=b; b= } printf(&The GCD of %d and %d is: %d\n&,num1,num2,a); printf(&The LCM of them is: %d\n&,num1*num2/a); } /*输出最大公约数*/ /*输出最小公倍数*/ /*采用辗转相除法求最大公约数*/ /*交换两个整数*/ /*找出两个数中的较大值*/ *运行结果 1.Input a & b: 20 55 The GCD of 20 and 55 is: 5 The LCM of them is: 220 2.Input a & b: 17 71The GCD of 17 and 71 is: 1 The LCM of them is: 1207 3.Input a & b: 24 88The GCD of 24 and 88 is: 8 The LCM of them is: 264 4.Input a & b: 35 85The GCD of 35 and 85 is: 5 The LCM of them is: 595 43.分数比较 比较两个分数的大小。 *问题分析与算法设计 人工方式下比较分数大小最常用的方法是:进行分数的通分后比较分子的大小。可以编程模拟手式方 式。 *程序与程序注释 #include&stdio.h& int zxgb(int a,int b); void main() { int i,j,k,l,m,n; printf(&Input two FENSHU:\n&); scanf(&%d/%d,%d/%d&,&i,&j,&k,&l); m=zxgb(j,l)/j*i; n=zxgb(j,l)/l*k; if(m&n) else } int zxgb(int a,int b) { if(a&b) c=a,a=b,b=c; for(c=a*b;b!=0;) { d=b; } b=a%b; a=d; /*若 a&b,则交换两变量的值*/ else if(m==n) /*输入两个分数*/ /*求出第一个分数通分后的分子*/ /*求出第二个分数通分后的分子*/ /*比较分子的大小*/ /*输出比较的结果*/ printf(&%d/%d=%d/%d\n&,i,j,k,l); printf(&%d/%d&%d/%d\n&,i,j,k,l);printf(&%d/%d&%d/%d\n&,i,j,k,l); return (int)c/a; } *运行结果 输入: 4/5,6/7 输入: 8/4,16/32 输入:16/32,4/8 44.分数之和 求这样的四个自然数 p,q,r,s(p&=q&=r&=s),使得以下等式成立: 1/p+1/q+1/r+1/s+1 输出: 4/5&6/7 输出: 8/4&16/32 输出: 16/32=4/8*问题分析与算法设计 若规定 p&=q&=r&=s,将原式通分、化简并整理后得到: 2&=p&5 程序与程序注释: #include&stdio.h& void main() { int p,q,r,s,count=0; printf(&The 4 fractions which sum is equal 1 are:\n&); for(p=2;p&5;p++) for(q=p;q&7;q++) for(r=q;r&13;r++) if(p*q*r-q*r-p*r-p*q!=0) { s=(p*q*r)/(p*q*r-q*r-p*r-p*q); printf(&[%2d] } } 45.将真分数分解为埃及分数 分子为 1 的分数称为埃及分数,现输入一个真分数,请将该分数分解为埃及分数。 如:8/11=1/2+1/5+1/55+1/110。 *问题分析与算法设计 若真分数的分子 a 能整除分母 b,则真分数经过化简就可以得到埃及分数,若真分数的分子不能整除分 母,则可以从原来的分数中分解出一个分母为 b/a+1 的埃及分数。用这种方法将剩余部分反复分解,最后 可得到结果。 *程序与程序注释 #include&stdio.h& void main() { long int a,b,c; /*求出 s 的值*/ if(!((p*q*r)%(p*q*r-q*r-p*r-p*q))&&s&=r) 1/%d+1/%d+1/%d+1/%d=1\n&,++count,p,q,r,s); /*输出结果*/ /*穷举分母*/ p&=q&7 q&r&13 采用最简单的穷举方法可以很方便的求解。 printf(&Please enter a optional fraction(a/b):&); scanf(&%ld/%ld&,&a,&b); while(1) { if(b%a) c=b/a+1; if(a==1) { printf(&1/%ld\n&,c); } else printf(&1/%ld + &,c); a=a*c-b; b=b*c; if(a==3) { } } *运行结果 1. Please enter a optional fraction (a/b): 1/6 It can be decomposed t 1/6 2. Please enter a optional fraction (a/b): 20/33 It can be decomposed t 1/2+1/10+1/165 3. Please enter a optional fraction (a/b): 10/89 It can be decomposed t 1/9+1/801 4. Please enter a optional fraction (a/b): 19/99 It can be decomposed t 1/6+1/40+1/3960 5. Please enter a optional fraction (a/b): 8/89 It can be decomposed t 1/11+1/957 46.列出真分数序列 按递增顺序依次列出所有分母为 40,分子小于 40 的最简分数。 *问题分析与算法设计 对分子采用穷举法,利用最大公约数的方法,判断分子与 40 是否构成真分数。 *程序与程序注释 #include&stdio.h& void main() { int i,num1,num2, printf(&The fraction serials with demominator 40 is:\n&); for(i=1;i&=40;i++) /*穷举 40 以内的全部分子*/ /*求出余数的分子*/ /*求出余数的分母*/ /*若余数为 3,输出最后两个埃及分数*/ /*a 为 1 标志结束*/ /*若分子不能整除分母*/ /*则分解出一个分母为 b/a+1 的埃及分数*/ /*输入分子 a 和分母 b*/ printf(&It can be decomposed t&);else{ c=b/a; a=1;} /*否则,输出化简后的真分数(埃及分数)*/printf(&1/%ld + 1/%ld\n&,b/2,b);} { num1=40; num2=i; while(num2!=0) { temp=num1%num2; num1=num2; num2= } if(num1==1) printf(&%d/40 } } *运行结果 The fraction serials with demominator 40 is: 1/40 21/40 *思考题 按递增顺序依次列出所有分母小于等于 40 的最简真分数 47.计算分数的精确值 使用数组精确计算 M/N(0&M&N&=100)的值。 如果 M/N 是无限循环小数, 则计算并输出它的第一循环节, 同时要求输出 循环节的起止位置(小数位的序号) *问题分析与算法设计 由于计算机字长的限制,常规的浮点运算都有精度限制,为了得到高精度的计算结果,就必须自行设计 实现方法。 为了实现高精度的计算,可将商存放在一维数组中,数组的每个元素存放一位十进制数,即商的第一位 存放在第一个元素中,商的第二位存放在第二个元素中....,依次类推。这样就可以使用数组不表示一个高 精度的计算结果。 进行除法运算时可以模拟人的手工操作, 即每次求出商的第一位后, 将余数乘以 10, 再计算商的下一位, 重复以上过程, 当某次计算后的余数为 0 时, 表示 M/N 为有限不循环小数某次计算后的余数与前面的某个 余数相同时,则 M/N 为无限循环小数,从该余数第一次出现之后所求得的各位数就是小数的循环节。 程序具体实现时,采用了数组和其它一些技巧来保存除法运算所得到的余数和商的各位数。 *程序与程序注释 #include&stdio.h& int remainder[101],quotient[101]; void main() { int m,n,i,j; printf(&Please input a fraction(m/n)(&0&m&n&=100):&); scanf(&%d/%d&,&m,&n); for(i=1;i&=100;i++) /*输入被除数和除数*/ /*i: 商的位数*/ printf(&%d/%d it's accuracy value is:0.&,m,n); /*remainder:存放除法的余数; quotient:依次存放商的每一位*/ 3/40 23/40 7/40 27/40 9/40 29/40 11/40 31/40 13/40 33/40 17/40 37/40 19/40 39/40 /*若最大公约数为 1,则为最简真分数*/ &,i); /*采用辗转相除法求出最大公约数*/ { remainder[m]=i; m*=10; quotient=m/n; m=m%n; if(m==0) { for(j=1;j&=1;j++) printf(&%d&,quotient[j]); } if(remainder[m]!=0) { for(j=1;j&=i;j++) printf(&%d&,quotient[j]); /*则输出循环小数*/ printf(&\n\tand it is a infinite cyclic fraction from %d\n&,remainder[m]); printf(&\tdigit to %d digit after decimal point.\n&,i); /*输出循环节的位置*/ } } } 51.谁是窃贼 公安人员审问四名窃贼嫌疑犯。已知,这四人当中仅有一名是窃贼,还知道这四人中每人要么是诚实的, 要么总是说谎的。在回答公安人员的问题中: 甲说: “乙没有偷,是丁偷的。 ” 乙说: “我没有偷,是丙便的。 ” 丙说: “甲没有偷,是乙偷的。 ” 丁说: “我没有偷。 ” 请根据这四人的答话判断谁是盗窃者。 *问题分析与算法设计 假设 A、B、C、D 分别代表四个人,变量的值为 1 代表该人是窃*。 由题目已知:四人中仅有一名是窃*,且这四个人中的每个人要么说真话,要么说假话,而由于甲、乙、 丙三人都说了两句话: “X 没偷,X 偷了” ,故不论该人是否说谎,他提到的两人中必有一人是小偷。故在列 条件表达式时,可以不关心谁说谎,谁说实话。这样,可以列出下列条件表达式: 甲说: ”乙没有偷,是丁偷的。 ” 乙说: “我没有偷,是丙偷有。 ” 丙说: “甲没有偷,是乙偷的。 ” 丁说: “我没有偷。 ” *程序与程序注释 #include&stdio.h& void main() { int i,j,a[4]; B+D=1 B+C=1 A+B=1 /*退出*/ /*若该余数对应的位在前面已经出现过*/ /*退出循环*/ /*输出商*/ /*m:除的余数 remainder[m]:该余数对应的商的位数*/ /*余数扩大 10 位*/ /*商*/ /*求余数*/ /*余数为 0 则表示是有限小数*/A+B+C+D=1其中丁只说了一句话,无法判定其真假,表达式反映了四人中仅有一名是窃*的条件。 for(i=0;i&4;i++) { for(j=0;j&4;j++) if(j==i)a[j]=1; else a[j]=0;/*假定只有第 i 个人为窃**/ /*将第 i 个人设置为 1 表示窃*,其余为 0*/if(a[3]+a[1]==1&&a[1]+a[2]==1&&a[0]+a[1]==1) { printf(&The thief is &); for(j=0;j&=3;j++) if(a[j])printf(&%c.&,j+'A'); printf(&\n&); } } } *运行结果 The thief is B. (乙为窃*。) /*成立*/ /*输出计算结果*//*判断条件是否成立*/---------------------------------------------------52.黑与白 有 A、B、C、D、E 五人,每人额头上都帖了一张黑或白的纸。五人对坐,每人都可以看到其它人额头 上的纸的颜色。五人相互观察后, A 说:“我看见有三人额头上帖的是白纸,一人额头上帖的是黑纸。” B 说:“我看见其它四人额头上帖的都是黑纸。” C 说:“我看见一人额头上帖的是白纸,其它三人额头上帖的是黑纸。” D 说:“我看见四人额头上帖的都是白纸。” E 什么也没说。 现在已知额头上帖黑纸的人说的都是谎话,额头帖白纸的人说的都是实话。问这五人谁的额头是帖白 纸,谁的额头是帖黑纸? *问题分析与算法设计 假如变量 A、B、C、D、E 表示每个人额头上所帖纸的颜色,0 代表是黑色,1 代表是白色。根据题目 中 A、B、C、D 四人所说的话可以总结出下列关系: A 说: a&&b+c+d+e==3||!a&&b+c+d+e!=3 B 说: b&&a+c+d+e==0||!b&&a+c+d+e!=0 C 说: c&&a+b+d+e==1||!c&&a+b+d+e!=1 D 说: d&&a+b+c+e==4||!d&&a+b+c+e!=4 穷举每个人额头所帖纸的颜色的所有可能的情况,代入上述表达式中进行推理运算,使上述表达式为 “真”的情况就是正确的结果。 *程序与程序注释 #include&stdio.h& void main() { int a,b,c,d,e; for(a=0;a&=1;a++) for(b=0;b&=1;b++) /*黑色:0 白色:1*/ /*穷举五个人额头帖纸的全部可能*/ for(c=0;c&=1;c++) for(d=0;d&=1;d++) for(e=0;e&=1;e++) if((a&&b+c+d+e==3||!a&&b+c+d+e!=3) &&(b&&a+c+d+e==0||!b&&a+c+d+e!=0) &&(c&&a+b+d+e==1||!c&&a+b+d+e!=1) &&(d&&a+b+c+e==4||!d&&a+b+c+e!=4)) { printf(&A is pasted a piece of %s paper on his forehead.\n&, a?&white&:&black&); printf(&B is pasted a piece of %s paper on his forehead.\n&, b?&white&:&black&); printf(&C is pasted a piece of %s paper on his forehead.\n&, c?&white&:&black&); printf(&D is pasted a piece of %s paper on his forehead.\n&, d?&white&:&black&); printf(&E is pasted a piece of %s paper on his forehead.\n&, e?&white&:&black&); } } *运行结果 A is pasted a paper of black paper on his forehead. B is pasted a paper of black paper on his forehead. C is pasted a paper of white paper on his forehead. D is pasted a paper of black paper on his forehead. E is pasted a paper of white paper on his forehead 53.迷语博士的难题(1) 诚实族和说谎族是来自两个荒岛的不同民族,诚实族的人永远说真话,而说谎族的人永远说假话。迷语 博士是个聪明的人,他要来判断所遇到的人是来自哪个民族的。 迷语博士遇到三个人,知道他们可能是来自诚实族或说谎族的。为了调查这三个人是什么族的,博士分 别问了他们的问题,这是他们的对话: 问第一个人: “你们是什么族?” ,答: “我们之中有两个来自诚实族。 ”第二个人说: “不要胡说,我们三 个人中只有一个是诚实族的。 ”第三个人听了第二个人的话后说: “对,就是只有一个诚实族的。 ” 请根据他的回答判断他们分别是哪个族的。 *问题分析与算法设计 假设这三个人分别为 A、B、C,若说谎其值为 0,若诚实,其值为 1。根据题目中三个人的话可分别列 出: 第一个人: a&&a+b+c==2||!a&&a+b+c!=2 第二个人: b&&a+b+c==1||!b&&a+b+c!=1 第三个人: c&&a+b+c==1||!c&&a+b+c!=1 利用穷举法,可以很容易地推出结果。 *程序与程序注释 #include&stdio.h& (黑) (黑) (白) (黑) (白) void main() { int a,b,c; for(a=0;a&=1;a++) for(b=0;b&=1;b++) for(c=0;c&=1;c++) if((a&&a+b+c==2||!a&&a+b+c!=2) /*判断是否满足题意*/ &&(b&&a+b+c==1||!b&&a+b+c!=1) &&(c&&a+b+c==1||!c&&a+b+c!=1)) { printf(&A is a %s.\n&,a?&honest&:&lier&); printf(&B is a %s.\n&,b?&honest&:&lier&); printf(&C is a %s.\n&,c?&honest&:&lier&); } } *运行结果 A is a lier B is a lier C is a lier *思考题 迷语博士遇到四个人,知道他们可能是来自诚实族和说谎族的。为了调查这四个人是什么族的,博士 照例进行询问:”你们是什么族的?“ 第一人说:”我们四人全都是说谎族的。“ 第二人说:”我们之中只有一人是说谎族的。“ 第三人说:”我们四人中有两个是说谎族的。“ 第四人说:”我是诚实族的。“ 问自称是“诚实族”的第四个人是否真是诚实族的? (答案:第四个人是诚实族的。) ---------------------------------------------------------54.迷语博士的难题(2) 两面族是荒岛上的一个新民族,他们的特点是说话真一句假一句且真假交替。如果第一句为真,则第 二句是假的;如果第一句为假的,则第二句就是真的,但是第一句是真是假没有规律。 迷语博士遇到三个人,知道他们分别来自三个不同的民族:诚实族、说谎族和两面族。三人并肩站在 博士前面。 博士问左边的人:“中间的人是什么族的?”,左边的人回答:“诚实族的”。 博士问中间的人:“你是什么族的?”,中间的人回答:“两面族的”。 博士问右边的人:“中间的人究竟是什么族的?”,右边的人回答:“说谎族的”。 请问:这三个人都是哪个民族的? *问题分析与算法设计 这个问题是两面族问题中最基本的问题,它比前面只有诚实族和说谎族的问题要复杂。解题时要使用 变量将这三个民族分别表示出来。 令:变量 A=1 表示:左边的人是诚实族的(用 C 语言表示为 A); (说谎族) (说谎族) (说谎族) /*输出判断结果*/ /*穷举每个人是说谎还是诚实的全部情况*/ /*说谎:0 诚实:1*/ 变量 B=1 表示:中间的人是诚实族的(用 C 语言表示为 B); 变量 C=1 表示:右边的人是诚实族的(用 C 语言表示为 C); 变量 AA=1 表示:左边的人是两面族的(用 C 语言表示为 AA); 变量 BB=1 表示:中间的人是两面族的(用 C 语言表示为 BB); 变量 CC=1 表示:右边的人是两面族的(用 C 语言表示为 CC); 则左边的人是说谎族可以表示为:A!=1 且 AA!=1 用 C 语言表示为:!A&&!AA 中间的人是说谎族可以表示为:B!=1 且 BB!=1 用 C 语言表示为:!B&&!BB 右边的人是说谎族可以表示为:C!=0 且 CC!=1 用 C 语言表示为:!C&&!CC 根据题目中“三人来自三个民族”的条件,可以列出: a+aa!=2&&b+bb!=2&&c+cc!=2 且 a+b+c==1&&aa+bb+cc==1 根据左边人的回答可以推出:若他们是诚实族,则中间的人也是诚实族;若他不是诚实族,则中间的 人也不是诚实族。以上条件可以表示为: c&&!b&&!bb||(!c&&!cc)&&(b||bb)||!c&&cc 将全部逻辑条件联合在一起,利用穷举的方法求解,凡是使上述条件同时成立的变量取值就是题目的 答案。 *程序与程序注释 #include&stdio.h& void main() { int a,b,c,aa,bb, for(a=0;a&=1;a++) for(b=0;b&=1;b++) for(c=0;c&=1;c++) for(aa=0;aa&=1;aa++) for(bb=0;bb&=1;bb++) for(cc=0;cc&=1;cc++) if(a+aa!=2&&b+bb!=2&&c+cc!=2&& a+b+c==1&&aa+bb+cc==1 !b { printf(&The man stand on left is a %s.\n&, aa?&double--dealer&:(a?&honest&:&lier&)); printf(&The man stand on left is a %s.\n&, bb?&double--dealer&:(b?&honest&:&lier&)); printf(&The man stand on left is a %s.\n&, cc?&double--dealer&:(c?&honest&:&lier&)); /*输出最终的推理结果*/ } } && && (a&&!aa&&b&&!bb||!a&&!b)&& (c&&!b&&!bb||(!c&&!cc)&&(b||bb)||!c&cc)) /*判断逻辑条件*/ /*穷举全部情况*/ (不是诚实族和两面族的人) *运行结果 The man stand on left is a double--dealer. The man stand on center is a lier. The man stand on right is a honest. *思考题 迷语博士遇到三个人,便问第一个人:“你是什么族的?”,回答:“诚实族的。”问第二个人:“你 是什么族的?”,答:“说谎族的。”博士又问第二个人:“第一个人真的是诚实族的吗?”,答:“是 的。”问第三个人:“你是什么族的?”,答:“诚实族的。”博士又问第三个人:“第一个人是什么族 的?”,答:“两面族的。” 请判断这个人到底是哪个民族的? (答案:第一个人是诚实族的,第二个人是两面族的,第三人是说谎族。) 55.哪个大夫哪天值班 医院有 A、B、C、D、E、F、G 七位大夫,在一星期内(星期一至星期天)每人要轮流值班一天。现在已 知: A 大夫比 C 大夫晚一天值班; D 大夫比 E 大夫晚二天值班; B 大夫比 G 大夫早三天值班; F 大夫的值班日在 B 和 C 大夫的中间,且是星期四; 请确定每天究竟是哪位大夫值班? *问题分析与算法设计 由题目可推出如下已知条件: *F 是星期四值班; *B 值班的日期在星期一至星期三,且三天后是 G 值班; *C 值班的日期在星期五至星期六,且一天后是 A 值班; *E 两天后是 D 值班;E 值班的日期只能在星期一至星期三; 在编程时用数组元素的下标 1 到 7 表示星期一到星期天,用数组元素的值分别表示 A~F 七位大夫。 *程序与程序注释 #include&stdio.h& #include&stdlib.h& int a[8]; char *day[]={&&,&MONDAY&,&TUESDAY&,&WEDNESDAY&,&THURSDAYT&, &FRIDAY&,&SATUDAY&,&SUNDAY&}; void main() { int i,j,t; a[4]=6; for(i=1;i&=3;i++) { a=2; /*星期四是 F 值班*/ /*建 立星期表*/ (左边的人是两面族的) (中间的人是说谎族的) (右边的人是诚实族的)/*假设 B 值班的日期*/ /*若三天后无人值班则安排 G 值班*/ /*否则 B 值班的日期不断对*/ /*假设 E 值班的时间*/if(!a[i+3]) a[i+3]=7; else{ a=0;} for(t=1;t&=3;t++) { if(!a[t]) a[t]=5; if(!a[t+2]) a[t+2]=4; else{ a[t]=0;} for(j=5;j&7;j++) { if(!a[j]) a[j]=3;/*若当天无人值班则安排 E 值班*/ /*若 E 值班两天后无人值班则应为 D*/ /*否则 E 值班的日期不对*//*若当天无人值班,则安排 C 值班*/if(!a[j+1]) a[j+1]=1; /*C 之后一天无人值班则应当是 A 值班*/ else{ a[j]=0;} for(i=1;i&=7;i++) exit(0); } } } } *运行结果 Doctor E is on duty MONDAY. Doctor B is on duty TUESDAY. Doctor D is on duty WEDNESDAY. Doctor F is on duty THUESDAY. Doctor G is on duty FRIDAY. Doctor C is on duty SATURDAY. Doctor A is on duty SUNDAY. *思考题 在本题的求解过程中,我们只考虑了一星期之内的情况,没有考虑跨周的情况。对于“B 大夫比 G 大 夫早三天值班的”条件只是简单的认为是在同一周内早三天。若考虑跨周的情况就可能出现:B 大夫星期 一值班,而 G 大夫是上周的星期五。同样,对“F 大夫的值班日在 B 和 C 大夫的中间”这个条件,也可以 扩展为:“只要 F 大夫的值班日在 B 和 C 大夫的中间就可以”。 请考虑允许跨周的情况下,可能的时间安排表。 ------------------------------------------------------56.区分旅客国籍 在一个旅馆中住着六个不同国籍的人,他们分别来自美国、德国、英国、法国、俄罗斯和意大利。他 们的名字叫 A、B、C、D、E 和 F。名字的顺序与上面的国籍不一定是相互对应的。现在已知: 1)A 美国人是医生。 2)E 和俄罗斯人是技师。 3)C 和德国人是技师。 4)B 和 F 曾经当过兵,而德国人从未参过军。 5)法国人比 A 年龄大;意大利人比 C 年龄大。 6)B 同美国人下周要去西安旅行,而 C 同法国人下周要去杭州度假。 试问由上述已知条件,A、B、C、D、E 和 F 各是哪国人? (星期一:E) (星期二:B) (星期三:D) (星期四:F) (星期五:G) (星期六:C) (星期日:A) /*否则 A 值班日期不对*/ /*安排完毕,输出结果*/printf(&Doctor %c is on duty %s.\n&,'A'+a-1,day); *问题分析与算法设计 首先进行题目分析,尽可能利用已知条件,确定谁不是哪国人。 由:1) 2) 3)可知:A 不是美国人,E 不是俄罗斯人,C 不是德国人。另外

我要回帖

更多关于 国际象棋谁先走 的文章

 

随机推荐