趣味语言

时间:2024.4.21

论幽默短信的结构和语用功能

自19xx年我国开通手机短信以来,几年时间,它已奇迹般地发展成为了继报纸杂志、广播、电视、网络之后的“第五媒体”。其中一种短信很是常见,如:快乐时有你的欢呼,伤心时有你的安慰,无聊时有你的陪伴??如果可以选择下辈子??我还要做你的??主人。这就是幽默短信,即有趣或可笑而意味深长的短信。本文拟对其话语结构和语用功能进行分析,以期更好的认识这一语言现象。 一、 研究现状

通过期刊网搜索,至今为止,发表研究短信的学术论文65篇,主要从短信的语体、修辞、文化等方面进行了探讨,如:《试论手机短信修辞手法的运用》(陈金凤,2005,《语文教学与研究》第5期);《手机短信话语文本的语体学分析》(孟建安,2004,《修辞学习》第4期);《后现代语境下的短信文化》(刘旭东,2004,《宜宾学院学报》第5期)等。本文拟从幽默短信的话语结构和语用功能方面进行论述,以求教于大家。

二、 幽默短信的结构

(一)表层结构

1.语音层面

在话语的语音层面上巧妙运用同音同形异义词,造成话语表层意义所称说的事物景象同深层意义上所陈述的情志思想叠合,相关涉,从而使幽默在特定的上下文中油然而生。例如:

(1)你的脸比陈世美还美,你的眼比诸葛亮还亮,我的爱比鲁智深还深,我的情比关云长还长,但我的诺言比孙悟空还空。

(2)你比镜子还能反映人的缺点,比庄子还博学多才,比孙子还有谋略,所以大家都亲切地叫你:镜庄孙子。

短信(1)断取大家所熟悉的人名的最后一个字“美”、“亮”、“深”、“长”、“空”,造成话语表层意义所称说的事物景象同深层意义上所陈述的情志思想叠合。短信(2)利用谐音来表达“净装孙子”的意思,从而增加了语趣。

2.句法结构

通过对句法结构的巧妙安排和变异来体现幽默效果。例如:

(3)我出一个对联,横批是“天蓬元帅”,上联是“在上为帅”,下联是什么?

(4)为什么大部分佛教徒都在北半球?——因为南“无”阿弥陀佛。 例(3)利用了“猪八戒”的身世背景:在天宫(在上)为帅,在人间(在下)为猪,同时“在下”如果在这里作主语,指短信接受者,如果“在下”作状语,为猪的就是“猪八戒”。例(4)中的“南无阿弥陀佛”是一句佛教用语,是一个语素,短信作者在这里把它看成一个句子,“南”作主语。

3.修辞手法

幽默短信往往运用修辞手法,以轻松揶揄的口吻善意调侃,拒绝沉重,拒绝严肃。例如:

你是多愁善感的乌鸦,你是活蹦乱跳的青蛙,你是出淤泥而不染的地瓜,你是我心中火红火红的大虾,我想轻轻地问候你:看短信的可爱的傻瓜,你现在好吗?

你美若天仙、漂亮大方、可爱迷人、纯情浪漫、冰雪聪明、温柔贤淑、体贴入微、尊老爱幼??以上所说的,都是我这么多年来对你的错误认识!

这两则短信分别运用了比喻、排比等修辞手法,更增添了短信的语趣。

4.语体交叉

语体交叉有两种方式:一是语言要素的渗透,就是指作为公文事务语体中书信体式的手机短信话语文本,在不改变本有的语体特征的前提下,渗透了其他语体的个别要素或部分要素为本语体增加不同的色彩,有意识地造成语体色彩的不协调美。例如:

删除昨天的烦恼,确定今天的快乐,设置明天的幸福,存储永远的爱心,取消时间的仇恨,粘贴美丽的心情,复制醉人的风景,打印你的笑容。

这则短信借用了计算机科学的一系列专用术语,使短信不但不生僻难懂,而因为表达者的巧妙配置显得更有情趣,更富有时代气息和年轻的朝气。

二是语文体式的的渗透,就是指借用诗歌、散文、剧本、对联、天气预报、说明文、歌曲等体式来创作手机幽默短信话语文本,达到一种幽默效果。例如: 女孩吃吧吃吧不是罪,再胖的人也有权利去增肥,苗条的背后其实是憔悴,爱你的人不会在乎你的腰围,尝尝阔别已久美食的滋味,就算撑死也是一种美。

这则短信借用了流行歌曲“男人哭吧哭吧不是罪”的体式,建议女孩不要因为要保持苗条的身材刻意节食,使短信话语不失诙谐幽默的情趣。

(二)幽默短信的深层结构

幽默短信的深层结构是一种特殊的“语言—心理”结构,在辩证逻辑的制约下,突破形式逻辑的一般规律,突破常规语言结构,变革运用语言材料,造成不能仅按字面意思来理解的话语,从而凸现幽默氛围。

1.语义方向突变—心理预期扑空

在实际的话语结构组合中,由于话语的基本命题或某些词语暗示,语义逻辑呈现一种发展方向,给读者一种心理预期,如果这一逻辑发展突然中断,“谜底”揭出的却是一种似乎与前面毫不相关的“最后结果”,即出现心理预期扑空,进而造成幽默氛围。例如:

让风撩起你的长发,你会显得更潇洒!让浪花拍打你的脚丫,你会显得更无暇!你迎着东方的朝霞,就像一朵海浪花!不是熟人很难看出你是傻瓜! 想你,在分分秒秒;爱你,至海枯石烂;陪你,至天涯海角;盼你,到山崩地裂;愿你??不要当真!

短信故意把“傻瓜”、“不要当真”等关键性话语放在最后,通过前面的话语给读者造成一种与结果完全不同的心理预期,又加上手机屏幕过小,刚开始不可能看到关键性话语结果。因此,短信看完时,心理预期扑空效果明显,从而造成幽默好笑的效果。在这里,表达者和接受者都有心理预期,表达者的心理预期是人为的、有准备的、主动的,有目的性的,而接受者的心理预期是随着表达者的“循循善诱”而被动产生的、无准备的。接受者之所以会产生心理预期,有心理学上的依据,从普通心理学的意义上看,大多数人都倾向于对已有表象进行改造而在心里形成新的形象。例如:“想你,在分分秒秒;爱你,至海枯石烂;陪你,至天涯海角;盼你,到山崩地裂;愿你??”即为表象信息,接受者都习惯于按经验知识对它加以联想和心理期待。

2.言语组合违反语言规则与社会习惯——经验与现实相矛盾

语言是约定俗成的符号系统,话语中的词语组合,既要受到语言体系的制约,又要受到语言社团习惯的制约,而且这种制约性必然在语言使用者个体的心理中形成一种经验感受和理性观念。当读者发现接收到的言语信息不合乎语言组合的

常规和社团使用习惯时,作为“解码规则”的语言经验和观念便与目前的话语事实发生矛盾冲突。在特定语境中,这种“矛盾冲突”往往会创造一种幽默意境, 例如:京城上下,顿失吵闹。吃板蓝根,服维生素,欲与SARS试比高。无宁日,看口罩手套,分外妖娆。

焦躁不安的情绪用轻松的口吻来诉说,复杂的生活用浓缩的语言来调侃,出其不意地抖出一个个“包袱”,有一点可笑,又有一点无奈,还带着一丝不屈不挠的乐观。

又如:老鼠没女朋友特别郁闷,终于一只蝙蝠答应嫁给他,老鼠十分高兴。别人笑话他没眼光,老鼠说:你们懂什么,她好歹是个空姐嘛!

面对现实,对不太如意的生活进行自我解嘲、自我调侃,而不是无病呻吟、哗众取宠,是一种对生活的真实体验和由衷感悟,是人们在深刻社会变革中对内心积郁情感的一种释放。

三、 幽默短信的语言功能

1.审美功能

幽默是艺术家对美爱到极致时的一种“逆向表现形式”。幽默作品以其独特的“内庄外谐”的言语组合形式寓深刻的社会内容于一体,不仅提供了一幅曲折而又真实地再现现实生活的图画,而且通过这幅寄寓着作家的某种社会理想与审美观念的图画来表现作家对生活的态度与评价。

如果有来世,就让我们做一对小小的老鼠吧。笨笨的相爱,呆呆的过日子,拙拙的依偎,傻傻的一起。即便大雪封山,还可以窝在暖暖的草堆紧紧的抱着咬你耳朵??

把你的影子/腌起来/风干/老的时候/下酒

这类短信不但语言优美,而且给人以想象,给人以意境,让读者有再创造和回味的余地,读者在阅读过程中和之后享受到一种审美愉悦。

2.交际功能

在特定语境中,幽默话语具有常规语言所达不到的特殊交际功能。在日常人际交往中,幽默话语是一种行之有效的交际手段,它可以用来弥合分歧,向人道歉,表示拒绝,进行批评,以及在不失面子的情况下让对方干你想让他干的事情。

如:远方的你可要好好照顾身体,不要感冒流鼻涕,偶尔也可以打几个喷嚏,那是代表我在想你。幽默短信的交际功能主要不在于给对方提供认知信息,而在于传递某种精神信息,或叫情感信息。亲朋戚友平日因为忙或者距离远而少相聚,通过短信,传递情谊,如例(15),既说出了当面可能不便于说的话,又表达了心中那份思念和牵挂。

总之,幽默短信既秉承了传统书面语言幽默的精髓,又有其内容和形式上的独特之处。既给人们带来开怀的笑容,又迅速成为了现代生活中不可或缺的“润滑剂”。


第二篇:c语言趣味题


C/C++语言经典、实用、趣味程序设计编程百例精解

1.绘制余弦曲线

在屏幕上用―*‖显示0~360度的余弦函数cos(x)曲线

*问题分析与算法设计

如果在程序中使用数组,这个问题十分简单。但若规定不能使用数组,问题就变得不容易了。 关键在于余弦曲线在0~360度的区间内,一行中要显示两个点,而对一般的显示器来说,只能按行输出,即:输出第一行信息后,只能向下一行输出,不能再返回到上一行。为了获得本文要求的图形就必须在一行中一次输出两个―*‖。

为了同时得到余弦函数cos(x)图形在一行上的两个点,考虑利用cos(x)的左右对称性。将屏幕的行方向定义为x,列方向定义为y,则0~180度的图形与180~360度的图形是左右对称的,若定义图形的总宽度为62列,计算出x行0~180度时y点的坐标m,那么在同一行与之对称的180~360度的y点的坐标就 应为62-m。程序中利用反余弦函数acos计算坐标(x,y)的对应关系。

使用这种方法编出的程序短小精炼,体现了一定的技巧。

*程序说明与注释

#include<stdio.h>

#include<math.h>

int main()

{

double y;

int x,m;

for(y=1;y>=-1;y-=0.1) /*y为列方向,值从1到-1,步长为0.1*/

{

m=acos(y)*10; /*计算出y对应的弧度m,乘以10为图形放大倍数*/

for(x=1;x<m;x++) printf(" ");

printf("*"); /*控制打印左侧的 * 号*/

for(;x<62-m;x++)printf(" ");

printf("*\n"); /*控制打印同一行中对称的右侧*号*/

}

return 0;

}

*思考题

如何实现用―*‖显示0~360度的sin(x)曲线。

在屏幕上显示0~360度的cos(x)曲线与直线f(x)=45*(y-1)+31的迭加图形。其中cos(x)图形用―*‖表示,f(x)用―+‖表示,在两个图形相交的点上则用f(x)图形的符号。

2.绘制余弦曲线和直线

*问题分析与算法设计

本题可以在上题的基础上进行修改。图形迭加的关键是要在分别计算出同一行中两个图形的列方

向点坐标后,正确判断相互的位置关系。为此,可以先判断图形的交点,再分别控制打印两个不同的图形。

*程序注释与说明

#include<stdio.h>

#include<math.h>

int main()

{

double y;

int x,m,n,yy;

for(yy=0;yy<=20;yy++) /*对于第一个y坐标进行计算并在一行中打印图形*/ {

y=0.1*yy; /*y:屏幕行方向坐标*/

m=acos(1-y)*10; /*m: cos(x)曲线上y点对应的屏幕列坐标*/

n=45*(y-1)+31; /*n: 直线上y点对应的列坐标*/

for(x=0;x<=62;x++) /*x: 屏幕列方向坐标*/

if(x==m&&x==n) printf("+"); /*直线与cos(x)相交时打印―+‖*/

else if(x==n) printf("+"); /*打印不相交时的直线图形*/

else if(x==m||x==62-m) printf("*"); /*打印不相交时的cos(x)图形*/

else printf(" "); /*其它情况打印空格*/

printf("\n");

}

return 0;

}

*思考题

如何实现sin(x)曲线与cos(x)曲线图形的同时显示。

3.绘制圆

在屏幕上用―*‖画一个空心的圆

*问题分析与算法设计

打印圆可利用图形的左右对称性。根据圆的方程:

R*R=X*X+Y*Y

可以算出圆上每一点行和列的对应关系。

*程序说明与注释

#include<stdio.h>

#include<math.h>

int main()

{

double y;

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("*"); /*圆的左侧*/

for(;x<30+m;x++) printf(" "); /*图形的空心部分控制*/

printf("*\n"); /*圆的右侧*/

}

return 0;

}

*思考题

实现函数y=x2的图形与圆的图形叠加显示

4.歌星大奖赛

在歌星大奖赛中,有10个评委为参赛的选手打分,分数为1~100分。选手最后得分为:去掉一个最高分和一个最低分后其余8个分数的平均值。请编写一个程序实现。

*问题分析与算法设计

这个问题的算法十分简单,但是要注意在程序中判断最大、最小值的变量是如何赋值的。 *程序说明与注释

#include<stdio.h>

int main()

{

int integer,i,max,min,sum;

max=-32768; /*先假设当前的最大值max为C语言整型数的最小值*/

min=32767; /*先假设当前的最小值min为C语言整型数的最大值*/

sum=0; /*将求累加和变量的初值置为0*/

for(i=1;i<=10;i++)

{

printf("Input number %d=",i);

scanf("%d",&integer); /*输入评委的评分*/

sum+=integer; /*计算总分*/

if(integer>max)max=integer; /*通过比较筛选出其中的最高分*/

if(integer<min)min=integer; /*通过比较筛选出其中的最低分*/

}

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>

int main()

{

long i;

int j;

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);

break;

}

}

*运行结果

输入:555555

输出:The max factor with 3 digits in 555555 is:777

6.高次方数的尾数

求13的13次方的最后三位数

*问题分析与算法设计

解本题最直接的方法是:将13累乘13次方截取最后三位即可。

但是由于计算机所能表示的整数范围有限,用这种―正确‖的算法不可能得到正确的结果。事实上,题目仅要求最后三位的值,完全没有必要求13的13次方的完整结果。

研究乘法的规律发现:乘积的最后三位的值只与乘数和被乘数的后三位有关,与乘数和被乘数的

高位无关。利用这一规律,可以大大简化程序。

*程序说明与注释

#include<stdio.h>

int 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++) /*X自乘Y次*/

last=last*x%1000; /*将last乘X后对1000取模,即求积的后三位*/

printf("The last 3 digits of %d**%d is:%d\n",x,y,last%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

7.阶乘尾数零的个数

100!的尾数有多少个零?

*问题分析与算法设计

可以设想:先求出100!的值,然后数一下末尾有多少个零。事实上,与上题一样,由于计算机所能表示的整数范围有限,这是不可能的。

为了解决这个问题,必须首先从数学上分析在100!结果值的末尾产生零的条件。不难看出:一个整数若含有一个因子5,则必然会在求100!时产生一个零。因此问题转化为求1到100这100个整数中包含了多少个因子5。若整数N能被25整除,则N包含2个因子5;若整数N能被5整除,则N包含1个因子5。

*程序说明与注释

#include<stdio.h>

int main()

{

int a,count =0;

for(a=5;a<=100;a+=5) //循环从5开始,以5的倍数为步长,考察整数

{

++count; //若为5的倍数,计数器加1

if(!(a%25)) ++count; //若为25的倍数,计数器再加1

}

printf("The number of 0 in the end of 100! is: %d.\n",count); //打印结果 return 0;

}

*运行结果

The number of 0 in the end of 100! is: 24.

*问题进一步讨论

本题的求解程序是正确的,但是存在明显的缺点。程序中判断整数N包含多少个因子5的方法是与程序中的100有关的,若题目中的100改为1000,则就要修改程序中求因子5的数目的算法了。

*思考题

修改程序中求因子5的数目的算法,使程序可以求出任意N!的末尾有多少个零。

8.借书方案知多少

小明有五本新书,要借给A,B,C三位小朋友,若每人每次只能借一本,则可以有多少种不同的借法?

*问题分析与算法设计

本问题实际上是一个排列问题,即求从5个中取3个进行排列的方法的总数。首先对五本书从1至5进行编号,然后使用穷举的方法。假设三个人分别借这五本书中的一本,当三个人所借的书的编号都不相同时,就是满足题意的一种借阅方法。

*程序说明与注释

int 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++) /*穷举第一个人借5本书中的1本的全部情况*/

for(b=1;b<=5;b++) /*穷举第二个人借5本书中的一本的全部情况*/

for(c=1;a!=b&&c<=5;c++) /*当前两个人借不同的书时,穷举第三个人借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 2: 1,2,4 3: 1,2,5 4: 1,3,2 5: 1,3,4

6: 1,3,5 7: 1,4,2 8: 1,4,3 9: 1,4,5 10:1,5,2

11:1,5,3 12:1,5,4 13:2,1,3 14:2,1,4 15:2,1,5

16:2,3,1 17:2,3,4 18:2,3,5 19:2,4,1 20:2,4,3

21:2,4,5 22:2,5,1 23:2,5,3 24:2,5,4 25:3,1,2

26:3,1,4 27:3,1,5 28:3,2,1 29:3,2,4 30:3,2,5

31:3,4,1 32:3,4,2 33:3,4,5 34:3,5,1 35:3,5,2

36:3,5,4 37:4,1,2 38:4,1,3 39:4,1,5 40:4,2,1

41:4,2,3 42:4,2,5 43:4,3,1 44:4,3,2 45:4,3,5

46:4,5,1 47:4,5,2 48:4,5,3 49:5,1,2 50:5,1,3

51:5,1,4 52:5,2,1 53:5,2,3 54:5,2,4 55:5,3,1

56:5,3,2 57:5,3,4 58:5,4,1 59:5,4,2 60:5,4,3

9.杨辉三角形

在屏幕上显示杨辉三角形

1

1 1

1 2 1

1 3 3 1

1 4 6 4 1

1 5 10 10 5 1

………………………………..

*问题分析与算法设计

杨辉三角形中的数,正是(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 x=1或x=N+1

c(x,y)=

c(x-1,y-1)+c(x-1,y) 其它

本程序应是根据以上递归的数学表达式编制的。

*程序说明与注释

#include<stdio.h>

int main()

{

int i,j,n=13;

printf("N=");

while(n>12)

scanf("%d",&n); /*控制输入正确的值以保证屏幕显示的图形正确*/

for(i=0;i<=n;i++) /*控制输出N行*/

{

for(j=0;j<24-2*i;j++) printf(" "); /*控制输出第i行前面的空格*/

for(j=1;j<i+2;j++) printf("%4d",c(i,j)); /*输出第i行的第j个值*/

printf("\n");

}

}

int c(int x,int y) /*求杨辉三角形中第x行第y列的值*/

{

int z;

if((y==1)||(y==x+1)) return 1; /*若为x行的第1或第x+1列,则输出1*/

z=c(x-1,y-1)+c(x-1,y); /*否则,其值为前一行中第y-1列与第y列值之和*/

return z;

}

*思考题

自行设计一种实现杨辉三角形的方法

10.数制转换

将任一整数转换为二进制形式

*问题分析与算法设计

将十进制整数转换为二进制的方法很多,这里介绍的实现方法利用了C语言能够对位进行操作的特点。对于C语言来说,一个整数在计算机内就是以二进制的形式存储的,所以没有必要再将一个整数经过一系列的运算转换为二进制形式,只要将整数在内存中的二进制表示输出即可。 *程序说明与注释

#include<stdio.h>

void printb(int,int);

int main()

{

int x;printf("Input number:");

scanf("%d",&x);

printf("number of decimal form:%d\n",x);

printf(" it's binary form:");

printb(x,sizeof(int)*8); /*x:整数 sizeof(int):int型在内存中所占的字节数

sizeof(int)*8:int型对应的位数*/

putchar('\n');

}

void printb(int x,int n)

{

if(n>0)

{

putchar('0'+((unsigned)(x&(1<<(n-1)))>>(n-1))); /*输出第n位*/

printb(x,n-1); /*归调用,输出x的后n-1位*/

}

}

*运行结果

输入:8

输出:

number of decimal form:8

it's bunary form:0000000000001000

输入:-8

输出:number of decimal form:-8

it's binary form:11xxxxxxxxxxxx0

输入:32767

输出:number of decimal form:32767

it's binary form:011xxxxxxxxxxxx

输入:-32768

输出:number of decimal form:-32768

it's binary form:1000000000000000

输入:128

输出:number of decimal form:128

it's binary form:0000000010000000

*问题的进一步讨论

充分利用C语言可以对位进行操作的特点,可以编写许多其它高级语言不便于编写甚至根本无法编写的程序。位操作是C语言的一大特点,在深入学习C语言的过程中应力求很好掌握。 程序中使用的位运算方法不是最佳的,也可以不用递归操作,大家可以自行对程序进行优化。 *思考题

将任意正整数转换为四进制或八进制数

11.打鱼还是晒网

中国有句俗语叫―三天打鱼两天晒网‖。某人从19xx年1月1日起开始―三天打鱼两天晒网‖,问这个人在以后的某一天中是―打鱼‖还是―晒网‖。

*问题分析与算法设计

根据题意可以将解题过程分为三步:

1)计算从19xx年1月1日开始至指定日期共有多少天;

2)由于―打鱼‖和―晒网‖的周期为5天,所以将计算出的天数用5去除;

3)根据余数判断他是在―打鱼‖还是在―晒网‖;

若 余数为1,2,3,则他是在―打鱼‖

否则 是在―晒网‖

在这三步中,关键是第一步。求从19xx年1月1日至指定日期有多少天,要判断经历年份中是否有闰年,二月为29天,平年为28天。闰年的方法可以用伪语句描述如下:

如果 ((年能被4除尽 且 不能被100除尽)或 能被400除尽)

则 该年是闰年;

否则 不是闰年。

C语言中判断能否整除可以使用求余运算(即求模)

*程序说明与注释

#include<stdio.h>

struct date{

int year;

int month;

int day;

};

int days(struct date day);

int main()

{

struct date today,term;

int yearday,year,day;

printf("Enter year/month/day:");

scanf("%d%d%d",&today.year,&today.month,&today.day); /*输入日期*/ term.month=12; /*设置变量的初始值:月*/

term.day=31; /*设置变量的初始值:日*/

for(yearday=0,year=1990;year<today.year;year++)

{

term.year=year;

yearday+=days(term); /*计算从19xx年至指定年的前一年共有多少天*/ }

yearday+=days(today); /*加上指定年中到指定日期的天数*/

day=yearday%5; /*求余数*/

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;

lp=day.year%4==0&&day.year%100!=0||day.year%400==0; /*判定year为闰年还是平年,lp=0为平年,非0为闰年*/

for(i=1;i<day.month;i++) /*计算本年中自1月1日起的天数*/

day.day+=day_tab[lp][i];

return day.day;

}

*运行结果

Enter year/month/day:1991 10 25

He was fishing at day.

Enter year/month/day:1992 10 25

He was sleeping at day.

Enter year/month/day:1993 10 25

He was sleeping at day.

*思考题

请打印出任意年份的日历

12.抓交通肇事犯

一辆卡车违反交通规则,撞人后逃跑。现场有三人目击事件,但都没有记住车号,只记下车号的一些特征。甲说:牌照的前两位数字是相同的;乙说:牌照的后两位数字是相同的,但与前两位不同; 丙是数学家,他说:四位的车号刚好是一个整数的平方。请根据以上线索求出车号。 *问题分析与算法设计

按照题目的要求造出一个前两位数相同、后两位数相同且相互间又不同的整数,然后判断该整数是否是另一个整数的平方。

*程序说明与注释

#include<stdio.h>

#include<math.h>

int main()

{

int i,j,k,c;

for(i=1;i<=9;i++) /*i:车号前二位的取值*/

for(j=0;j<=9;j++) /*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%。现在某人手中有一笔钱,他打算在今后的五年中的年底取出1000元,到第五年时刚好取完,请算出他存钱时应存入多少。

*问题分析与算法设计

分析存钱和取钱的过程,可以采用倒推的方法。若第五年年底连本带息要取1000元,则要先求出第五年年初银行存款的钱数:

第五年初存款=1000/(1+12*0.0063)

依次类推可以求出第四年、第三年……的年初银行存款的钱数:

第四年年初存款=(第五年年初存款+1000)/(1+12*0.0063)

第三年年初存款=(第四年年初存款+1000)/(1+12*0.0063)

第二年年初存款=(第三年年初存款+1000)/(1+12*0.0063)

第一年年初存款=(第二年年初存款+1000)/(1+12*0.0063)

通过以上过程就可以很容易地求出第一年年初要存入多少钱。

*程序说明与注释

#include<stdio.h>

int main()

{

int i;

float total=0;

for(i=0;i<5;i++) /*i 为年数,取值为0~4年*/

total=(total+1000)/(1+0.0063*12); /*累计算出年初存款数额,第五次的计算 结果即为题解*/

printf("He must save %.2f at first.\n",total);

}

*运行结果

He must save 4039.44 at first

14.怎样存钱利最大

假设银行整存整取存款不同期限的月息利率分别为:

0.63% 期限=1年

0.66% 期限=2年

0.69% 期限=3年

0.75% 期限=5年

0.84% 期限=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>

int main()

{

int i8,i5,i3,i2,i1,n8,n5,n3,n2,n1;

float max=0,term;

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=term;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(" made fixed deposit for 8 year: %d times\n",n8);

printf(" made fixed deposit for 5 year: %d times\n",n5);

printf(" made fixed deposit for 3 year: %d times\n",n3);

printf(" made fixed deposit for 2 year: %d times\n",n2);

printf(" made fixed deposit for 1 year: %d times\n",n1);

printf(" Toal: %.2f\n",max);

/*输出存款方式*/

}

*运行结果

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年期。

*思考题

某单位对职工出售住房,每套为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>

int main()

{

int n,i,x,flag=1; /*flag:控制标记*/

for(n=6;flag;n++) /*采用试探的方法。令试探值n逐步加大*/

{

for(x=n,i=1&&flag;i<=5;i++)

if((x-1)%5==0) x=4*(x-1)/5;

else flag=0; /*若不能分配则置标记falg=0退出分配过程*/

if(flag) break; /*若分配过程正常结束则找到结果退出试探的过程*/

else flag=1; /*否则继续试探下一个数*/

}

printf("Total number of fish catched=%d\n",n); /*输出结果*/

}

*运行结果

Total number of fish catched = 3121

*问题的进一步讨论

程序采用试探法,试探的初值为6,每次试探的步长为1。这是过分保守的做法。可以在进一步分析题目的基础上修改此值,增大试探的步长值,以减少试探次数。

*思考题

请使用其它的方法求解本题。

16.出售金鱼

买卖提将养的一缸金鱼分五次出售系统上一次卖出全部的一半加二分之一条;第二次卖出余下的三分之一加三分之一条;第三次卖出余下的四分之一加四分之一条;第四次卖出余下的五分之一加五分之一条;最后卖出余下的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>

int main()

{

int i,j,n=0,x; /*n为标志变量*/

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;break;} /*否则停止计算过程*/

if(j==5&&x==11) /*若第四次余下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给老大‖。结果大家手中的桔子正好一样多。问六兄弟原来手中各有多少桔子?

17.有限5位数

个位数为6且能被3整除的五位数共有多少?

*题目分析与算法设计

根据题意可知,满足条件的五位数的选择范围是10006、10016。。。99996。可设基础数i=1000,通过计算i*10+6即可得到欲选的数(i的变化范围是1000~999),再判断该数能否被3整除。

*程序说明与注释

#include<stdio.h>

int main()

{

long int i;

int count=0; /*count:统计满足条件的五位数的个数*/

for(i=1000;i<9999;i++)

if(!((i*10+6)%3)) /*判断所选的数能否被3整除*/

count++; /*若满足条件则计数*/

printf("count=%d\n",count);

}

*运行结果

count=2999

*思考题

求100到1000之间有多少个其数字之和为5的整数。

(答案:104,113,122,131,140,203,212,221,230,302,311,320,401,410,500)

18.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>

int main()

{

int i;

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);

break; /*退出循环*/

}

}

*运行结果

The required number is:1993

19.一个奇异的三位数

一个自然数的七进制表达式是一个三位数,而这个自然数的九进制表示也是一个三位数,且这两个三位数的数码正好相反,求这个三位数。

*问题分析与算法设计

根据题意可知,七进制和九进制表示的这全自然数的每一位一定小于7,可设其七进制数形式为kji(i、j、k的取值分别为1~6),然后设其九进制表示形式为ijk。

*程序说明与注释

#include<stdio.h>

int 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)

20.位反序数

设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>

int main()

{

int i;

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

21.求车速

一辆以固定速度行驶的汽车,司机在上午10点看到里程表上的读数是一个对称数(即这个数从左向右读和从右向左读是完全一样的),为95859。两小时后里程表上出现了一个新的对称数。问该车的速度是多少?新的对称数是多少?

*问题分析与算法设计

根据题意,设所求对称数为i,其初值为95589,对其依次递增取值,将i值的每一位分解后与其对称位置上的数进行比较,若每个对称位置上的数皆相等,则可判定i即为所求的对称数。 *程序说明与注释

#include<stdio.h>

int main()

{

int t,a[5]; /*数组a存放分解的数字位*/

long int k,i;

for(i=95860;;i++) /*以95860为初值,循环试探*/

{

for(t=0,k=100000;k>=10;t++) /*从高到低分解所取i值的每位数*/

{ /* 字,依次存放于a[0]~a[5]中*/

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-95859)/2.0);

break;

}

}

}

*运行结果

The new symmetrical number kelometers is:95959.

The velocity of the car is:50.00

*思考题

将一个数的数码倒过来所得到的新数叫原数的反序数。如果一个数等于它的反序数,则称它为对称数。求不超过1993的最大的二进制的对称数。

22.由两个平方三位数获得三个平方二位数

已知两个平方三位数abc和xyz,其中a、b、c、x、y、z未必是不同的;而ax、by、cz是三个平方二位数。请编程求三位数abc和xyz。

*问题分析与算法设计

任取两个平方三位数n和n1,将n从高向低分解为a、b、c,将n1从高到低分解为x、y、z。判断ax、by、cz是否均为完全平方数。

*程序说明与注释

#include<stdio.h>

#include<math.h>

void f(int n,float* s);

int main()

{

int i,t;

float a[3],b[3];

print("The possible perfect squares combinations are:\n");

for(i=11;i<=31;++i) //穷举平方三位数的取值范围

for(t=11;t<=31;++t)

{

f(i*i,a); //分解平方三位数的各位,每位数字分别存入数组中

f(t*t,b);

if(sqrt(a[0]*10+b[0]) == (int)sqrt(a[0]*10+b[0])

&& sqrt(a[1]*10+b[1]) == (int)sqrt(a[1]*10+b[1])

&& sqrt(a[2]*10+b[2]) == (int)sqrt(a[2]*10+b[2]) )

{

printf("%d and %d\n,i*i,t*t"); //若三个新的数均是完全平方数,则输出

}

}

}

/* ———————————————-

分解三位数n的各位数字,将各个数字从高到低依次存入指针s所指向的数组中

————————————————*/

void f(int n,float* s)

{

int k;

for(k=1000;k>=10;++s)

{

*s = (n%k) /(k/10);

k /=10;

}

}

*运行结果

The possible perfect squares combinations are:

400 and 900

841 and 196

*思考题

求这样一个三位数,该三位数等于其每位数字的阶乘之和。

即 abc = a! + b! + c!

(正确结果:145 = 1! + 4! +5!)

23.阿姆斯特朗数

如果一个正整数等于其各个数字的立方和,则称该数为阿姆斯特朗数(亦称为自恋性数)。 如 407=43+03+73就是一个阿姆斯特朗数。试编程求1000以内的所有阿姆斯特朗数。 *问题分析与算法设计

可采用穷举法,依次取1000以内的各数(设为i),将i的各位数字分解后,据阿姆斯特朗数的性质进行计算和判断。

*程序说明与注释

#include<stdio.h>

int main()

{

int i,t,k,a[3];

printf("There are follwing Armstrong number smaller than 1000:\n");

for(i=2;i<1000;i++) /*穷举要判定的数i的取值范围2~1000*/

{

for(t=0,k=1000;k>=10;t++) /*截取整数i的各位(从高向低位)*/

{

a[t]=(i%k)/(k/10); /*分别赋于a[0]~a[2}*/

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 1000:

153 370 371 407

24.完全数

如果一个数恰好等于它的因子之和,则称该数为―完全数‖。

*问题分析与算法设计

根据完全数的定义,先计算所选取的整数a(a的取值1~1000)的因子,将各因子累加于m,若m等于a,则可确认a为完全数。

*程序说明与注释

#include<stdio.h>

int 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++) /*计算a的因子,并将各因子之和m=a,则a是完全数输出*/ if(!(a%i))m+=i;

if(m==a)

printf("%4d ",a);

}

printf("\n");

}

*运行结果

TThere are following perfect numbers smaller than 1000:

6 28 496

25.亲密数

如果整数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>

int main()

{

int a,i,b,n;

printf("There are following friendly–numbers pair smaller than 3000:\n"); for(a=1;a<3000;a++) /*穷举1000以内的全部整数*/

{

for(b=0,i=1;i<=a/2;i++) /*计算数a的各因子,各因子之和存放于b*/

if(!(a%i))b+=i; /*计算b的各因子,各因子之和存于n*/

for(n=0,i=1;i<=b/2;i++)

if(!(b%i))n+=i;

if(n==a&&a<b)

printf("%4d..%4d ",a,b); /*若n=a,则a和b是一对亲密数,输出*/

}

}

*运行结果

There are following friendly–numbers pair smaller than 3000:

220.. 284 1184.. 1210 2620.. 2924

26.自守数

自守数是指一个数的平方的尾数等于该数自身的自然数。例如:

252=625 762=5776 93762=87909376

请求出200000以内的自守数

*问题分析与算法设计

若采用―求出一个数的平方后再截取最后相应位数‖的方法显然是不可取的,因为计算机无法表示过大的整数。

分析手工方式下整数平方(乘法)的计算过程,以376为例:

376 被乘数

X 376 乘数

———-

2256 第一个部分积=被乘数*乘数的倒数第一位

2632 第二个部分积=被乘数*乘数的倒数第二位

1128 第三个部分积=被乘数*乘数的倒数第三位

———-

141376 积

本问题所关心的是积的最后三位。分析产生积的后三位的过程,可以看出,在每一次的部分积中,并不是它的每一位都会对积的后三位产生影响。总结规律可以得到:在三位数乘法中,对积的后三位产生影响的部分积分别为:

第一个部分积中:被乘数最后三位*乘数的倒数第一位

第二个部分积中:被乘数最后二位*乘数的倒数第二位

第三个部分积中:被乘数最后一位*乘数的倒数第三位

将以上的部分积的后三位求和后截取后三位就是三位数乘积的后三位。这样的规律可以推广到同样问题的不同位数乘积。

按照手工计算的过程可以设计算法编写程序。

*程序说明与注释

#include<stdio.h>

int main()

{

long mul,number,k,ll,kk;

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; /*kk为截取部分积时的系数*/

mul=0; /*积的最后n位*/

ll=10; /*ll为截取乘数相应位时的系数*/

while(k>0)

{

mul=(mul+(number%(k*10))*(number%ll-number%(ll/10)))%kk;

/*(部分积+截取被乘数的后N位*截取乘数的第M位),%kk再截取部分积*/

k/=10; /*k为截取被乘数时的系数*/

ll*=10;

}

if(number==mul) /*判断若为自守数则输出*/

printf("%ld ",number);

}

}

*运行结果

It exsts following automorphic numbners smaller than 200000:

0 1 5 6 25 76 376 625 9376 90625 109376

27.回文数

打印所有不超过n(取n<256) 的其平方具有对称性质的数(也称回文数)。

*问题分析与算法设计

对于要判断的数n,计算出其平方后(存于a),将a的每一位进行分解,再按a的从低到高的顺序将其恢复成一个数k(如n=13,则a=169且k=961),若a等于k则可判定n为回亠数。 *程序说明与注释

原程序好像有错,而且比较费解,现基于原程序修改如下(如果读者还发现错误请提出): #include<stdio.h>

int main(void)

{

int m[16],n,i,t,count=0;

long unsigned a,k;

printf("No. number it's square(palindrome)\n");

for(n=1;n<256;n++) /*穷举n的取值范围*/

{

k=0;t=1;a=n*n; /*计算n的平方*/

for(i=0;a!=0;i++) /*从低到高分解数a的每一位存于数组m[0]~m[16]*/

{

m[i]=a%10;//这个是取得a的个位,整个循环合起来就可以取得各个位

a/=10;

}

int j=0;

for(i–;j<i;j++,i–)//因为n的平方的各个位都存在数组中了,下面判断是不是对称 if(m[j]!=m[i])break;//只要有一位不是对称,那就说明不是对称,就可以退出了

//所有的位都对称就说明是对称了,这样就可以打印出结果了

if(j>=i)printf("%2d%10d%10d\n",++count,n,n*n);

}

return 0;

}

*运行结果

No. number it's square(palindrome)

1 1 1

2 2 4

3 3 9

4 11 121

5 22 484

6 26 676

7 101 10201

8 111 12321

9 121 14641

10 202 40804

11 212 44944

28.求具有abcd=(ab+cd)2性质的四位数

3025这个数具有一种独特的性质:将它平分为二段,即30和25,使之相加后求平方,即(30+25)2,恰好等于3025本身。请求出具有这样性质的全部四位数。

*问题分析与算法设计

具有这种性质的四位数没有分布规律,可以采用穷举法,对所有四位数进行判断,从而筛选出符合这种性质的四位数。具体算法实现,可任取一个四位数,将其截为两部分,前两位为a,后两位为b,然后套用公式计算并判断。

*程序说明与注释

#include<stdio.h>

int main()

{

int n,a,b;

printf("There are following number with 4 digits satisfied condition\n");

for(n=1000;n<10000;n++) /*四位数N的取值范围1000~9999*/

{

a=n/100; /*截取N的前两位数存于a*/

b=n%100; /*截取N的后两位存于b*/

if((a+b)*(a+b)==n) /*判断N是否为符合题目所规定的性质的四位数*/

printf("%d ",n);

}

}

*运行结果

There are following numbers with 4 digits satisfied condition:

2025 3025 9801

29.求素数

求素数表中1~1000之间的所有素数

*问题分析与算法设计

素数就是仅能衩1和它自身整除的整数。判定一个整数n是否为素数就是要判定整数n能否被除1和它自身之外的任意整数整除,若都不能整除,则n为素数。

程序设计时i可以从2开始,到该整数n的1/2为止,用i依次去除需要判定的整数,只要存在可以整除该数的情况,即可确定要判断的整数不是素数,否则是素数。

*程序说明与注释

#include<stdio.h>

int 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)); /*输入正确的范围*/

printf("………..PRIME TABLE(%d–%d)…………\n",n1,nm);

if(n1==1||n1==2) /*处理素数2*/

{

printf("%4d",2);

n1=3;count++;

}

for(i=n1;i<=nm;i++) /*判定指定范围内的整数是否为素数*/

{

if(!(i%2))continue;

for(flag=1,j=3;flag&&j<i/2;j+=2)

/*判定能否被从3到整数的一半中的某一数所整除*/

if(!(i%j))flag=0; /*若能整除则不是素数*/

if(flag) printf(++count%15?"%4d":"%4d\n",i);

}

}

*思考题

请找出十个最小的连续自然数,它们个个都是合数(非素数)

30.百钱百鸡问题

中国古代数学家张丘建在他的《算经》中提出了著名的―百钱买百鸡问题‖:鸡翁一,值钱五,鸡母一,值钱三,鸡雏三,值钱一,百钱买百鸡,问翁、母、雏各几何?

*问题分析与算法设计

设鸡翁、鸡母、鸡雏的个数分别为x,y,z,题意给定共100钱要买百鸡,若全买公鸡最多买20只,显然x的值在0~20之间;同理,y的取值范围在0~33之间,可得到下面的不定方程: 5x+3y+z/3=100

x+y+z=100

所以此问题可归结为求这个不定方程的整数解。

由程序设计实现不定方程的求解与手工计算不同。在分析确定方程中未知数变化范围的前提下,可通过对未知数可变范围的穷举,验证方程在什么情况下成立,从而得到相应的解。 *程序说明与注释

#include<stdio.h>

int 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++) /*内层循环控制鸡母数y在0~33变化*/

{

z=100-x-y; /*内外层循环控制下,鸡雏数z的值受x,y的值的制约*/

if(z%3==0&&5*x+3*y+z/3==100)

/*验证取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

*问题的进一步讨论

这类求解不定方程总理的实现,各层循环的控制变量直接与方程未知数有关,且采用对未知数的取值范上穷举和组合的方法来复盖可能得到的全部各组解。能否根据题意更合理的设置循环控制条件来减少这种穷举和组合的次数,提高程序的执行效率,请读者考虑

31.爱因斯坦的数学题

爱因斯坦出了一道这样的数学题:有一条长阶梯,若每步跨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>

int main()

{

int i=1; /*i为所设的阶梯数*/

while(!((i%2==1)&&(i%3==2)&&(i%5==4)&&(i%6==5)&&(i%7==0)))

++i; /*满足一组同余式的判别*/

printf("Staris_number=%d\n",i);

}

*运行结果

Staris_number=119

*问题的进一步讨论

此题算法还可考虑求1、2、4、5的最小公倍数n,然后判t(t为n-1)≡0(mod7)是否成立,若不成立则t=t+n,再进行判别,直至选出满足条件的t值。请自行编写程序实现

32.换分币

用一元人民币兑换成1分、2分和5分硬币,共有多少种不同的兑换方法。

*问题分析与算法设计

根据题意设i,j,k分别为兑换的1分、2分、5分硬币所具有的钱数(分),则i,j,k的值应满足: i+j+k=100

*程序说明与注释

#include<stdio.h>

int 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++) /*i为1分硬币钱数,可取值0,1,2…,100*/

for(j=0;j<=100-i;j+=2) /*j为2分硬币钱数,可取0值,2,4,…,100*/

for(k=0;k<=100-i-2*j;k+=5) /*k为5分硬币钱数*/

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);

}

33.年龄几何

张三、李四、王五、刘六的年龄成一等差数列,他们四人的年龄相加是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>

int main()

{

int n,a,i;

printf("The series with equal difference are:\n");

for(n=1;n<=6;n++) /*公差n取值为1~6*/

for(a=1;a<=4;a++) /*首项a取值为1~4*/

if(4*n+6*a==26&&n*(n+a)*(n+a+a)*(n+a+a+a)==880) /*判断结果*/

for(i=0;i<20;i++)

printf("%d ",n+i*a); /*输出前20项*/

}

*运行结果

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

34.三色球问题

若一个口袋中放有12个球,其中有3个红的。3个白的和6个黒的,问从中任取8个共有多少种不同的颜色搭配?

*问题分析与算法设计

设任取的红球个数为i,白球个数为j,则黒球个数为8-i-j,根据题意红球和白球个数的取值范围是0~3,在红球和白球个数确定的条件下,黒球个数取值应为8-i-j<=6。

*程序说明与注释

#include<stdio.h>

int main()

{

int i,j,count=0;

printf(" RED BALL WHITE BALL BLACKBALL\n");

printf("…………………………………………..\n");

for(i=0;i<=3;i++) /*循环控制变量i控制任取红球个数0 ̄3*/

for(j=0;j<=3;j++) /*循环控制变量j控制任取白球个数0 ̄3*/

if((8-i-j)<=6)

printf(" %2d: %d %d %d\n",++count,i,j,8-i-j);

}

35.马克思手稿中的数学题

马克思手稿中有一道趣味数学问题:有30个人,其中有男人、女人和小孩,在一家饭馆吃饭花了50先令;每个男人花3先令,每个女人花2先令,每个小孩花1先令;问男人、女人和小孩各有几人?

*问题分析与算法设计

设x,y,z分别代表男人、女人和小孩。按题目的要求,可得到下面的方程:

x+y+z=30 (1)

3x+2y+z=50 (2)

用方程程序求此不定方程的非负整数解,可先通过(2)-(1)式得:

2x+y=20 (3)

由(3)式可知,x变化范围是0~10

*程序说明与注释

#include<stdio.h>

int main()

{

int x,y,z,count=0;

printf(" Men Women Children\n");

printf("?????????????.\n");

for(x=0;x<=10;x++)

{

y=20-2*x; /*x定值据(3)式求y*/

z=30-x-y; /*由(1)式求z*/

if(3*x+2*y+z==50) /*当前得到的一组解是否满足式(2)*/

printf(" %2d: %d %d %d\n",++count,x,y,z);

}

}

36.最大公约数和最小公倍数

求任意两个正整数的最大公约数和(GCD)和最小公倍数(LCM)

*问题分析与算法设计

手工方式求两个正整数的蝚大公约数的方法是用辗转相除法,在程序中可以模拟这种方式。 *程序说明与注释

#include<stdio.h>

int main()

{

int a,b,num1,num2,temp;

printf("Input a & b:");

scanf("%d%d",&num1,&num2);

if(num1>num2) /*找出两个数中的较大值*/

{

temp=num1; num1=num2; num2=temp; /*交换两个整数*/

}

a=num1; b=num2;

while(b!=0) /*采用辗转相除法求最大公约数*/

{

temp=a%b;

a=b;

b=temp;

}

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 71

The GCD of 17 and 71 is: 1

The LCM of them is: 1207

3.Input a & b: 24 88

The GCD of 24 and 88 is: 8

The LCM of them is: 264

4.Input a & b: 35 85

The GCD of 35 and 85 is: 5

The LCM of them is: 595

*思考题

求一个最小的正整数,这个正整数被任意n(2<=n<=10)除都是除不尽的,而且余数总是(n-1)。例如:被9除时的余数为8。要求设计一个算法,不允许枚举与除2、除3、?.、除9、除10有关的命令,求出这个正整数。

37.新娘和新郞

三对情侣参加婚礼,三个新郞为A、B、C,三个新娘为X、Y、Z。有人不知道谁和谁结婚,于是询问了六位新人中的三位,但听到的回答是这样的:A说他将和X结婚;X说她的未婚夫是C;C说他将和Z结婚。这人听后知道他们在开玩笑,全是假话。请编程找出谁将和谁结婚。 *问题分析与算法设计

将A、B、C三人用1,2,3表示,将X和A结婚表示为“X=1”,将Y不与A结婚表示为“Y!=1”。按照题目中的叙述可以写出表达式:

x!=1 A不与X结婚

x!=3 X的未婚夫不是C

z!=3 C不与Z结婚

题意还隐含着X、Y、Z三个新娘不能结为配偶,则有:

x!=y且x!=z且y!=z

穷举以上所有可能的情况,代入上述表达式中进行推理运算,若假设的情况使上述表达式的结果均为真,则假设情况就是正确的结果。

*程序说明与注释

#include<stdio.h>

int main()

{

int x,y,z;

for(x=1;x<=3;x++) /*穷举x的全部可能配偶*/

for(y=1;y<=3;y++) /*穷举y的全部可能配偶*/

for(z=1;z<=3;z++) /*穷举z的全部可能配偶*/

if(x!=1&&x!=3&&z!=3&&x!=y&&x!=z&&y!=z) /*判断配偶是否满足题意*/

{

printf("X will marry to %c.\n",'A'+x-1); /*打印判断结果*/

printf("Y will marry to %c.\n",'A'+y-1);

printf("Z will marry to %c.\n",'A'+z-1);

}

}

*运行结果

X will marry to B. (X与B结婚)

Y will marry to C. (Y与C结婚)

Z will marry to A. (Z与A结婚)

38.委派任务

某侦察队接到一项紧急任务,要求在A、B、C、D、E、F六个队员中尽可能多地挑若干人,但有以下限制条件:

1)A和B两人中至少去一人;

2)A和D不能一起去;

3)A、E和F三人中要派两人去;

4)B和C都去或都不去;

5)C和D两人中去一个;

6)若D不去,则E也不去。

问应当让哪几个人去?

*问题分析与算法设计

用A、B、C、D、E、F六个变量表示六个人是否去执行任务的状态,变量的值为1,则表示该人去;变量的值为0,则表示该人不参加执行任务,根据题意可写出表达式:

a+b>1 A和B两人中至少去一人;

a+d!=2 A和D不能一起去;

a+e+f==2 A、E、F三人中要派两人去;

b+c==0或b+c==2 B和C都去或都不去;

c+d==1 C和D两人中去一个;

d+e==0或d==1 若D不去,则E也不去(都不去;或D去E随便)。

上述各表达式之间的关系为“与”关系。穷举每个人去或不去的各种可能情况,代入上述表达式中进行推理运算,使上述表达式均为“真”的情况就是正确的结果。

*程序说明与注释

#include<stdio.h>

int main()

{

int a,b,c,d,e,f;

for(a=1;a>=0;a–) /*穷举每个人是否去的所有情况*/

for(b=1;b>=0;b–) /*1:去 0:不去*/

for(c=1;c>=0;c–)

for(d=1;d>=0;d–)

for(e=1;e>=0;e–)

for(f=1;f>=0;f–)

if(a+b>=1&&a+d!=2&&a+e+f==2

&&(b+c==0||b+c==2)&&c+d==1

&&(d+e==0||d==1))

{

printf("A will%s be assigned. \n",a?"":"not");

printf("B will%s be assigned. \n",b?"":"not");

printf("C will%s be assigned. \n",c?"":"not");

printf("D will%s be assigned. \n",d?"":"not");

printf("E will%s be assigned. \n",e?"":"not");

printf("F will%s be assigned. \n",f?"":"not");

}

}

*运行结果

A will be assigned. (去)

B will be assigned. (去)

C will be assigned. (去)

D will not be assigned. (不去)

E will not be assigned. (不去)

F will be assigned. (去)

*思考题

某参观团按以下条件限制从A、B、C、D、E五个地方中选若干参观点:

1)如去A,则必须去B;

2)D、E两地只能去一地;

3)B、C两地只能去一地;

4)C、D两地都去或都不去;

5)若去E地,A、D也必去。

问该团最多能去哪几个地方?

39.谁在说谎

张三说李四在说谎,李四说王五在说谎,王五说张三和李四都在说谎。现在问:这三人中到底谁说的是真话,谁说的是假话?

*问题分析与算法设计

分析题目,每个人都有可能说的是真话,也有可能说的是假话,这样就需要对每个人所说的话进行分别判断。假设三个人所说的话的真假用变量A、B、C表示,等于1表示该人说的是真话; 表示这个人说的是假话。由题目可以得到:

*张三说李四在说谎 张三说的是真话:a==1&&b==0

或 张三说的是假话:a==0&&b==1

*李四说王五在说谎 李四说的是真话:b==1&&c==0

或 李四说的是假话:b==0&&c==1

*王五说张三和李四都在说谎 王五说的是真话:c==1&&a+b==0

或 王五说的是假话:c==0&&a+b!=0

上述三个条件之间是“与”的关系。将表达式进行整理就可得到C语言的表达式:

(a&&!b||!a&&b)&&(b&&!c||!b&&c)&&(c&&a+b==0||!c&&a+b!=0)

穷举每个人说真话或说假话的各种可能情况,代入上述表达式中进行推理运算,使上述表达式均为“真”的情况就是正确的结果。

*程序说明与注释

#include<stdio.h>

int 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&&!b||!a&&b)&&(b&&!c||!b&&c)&&(c&&a+b==0||!c&&a+b!=0))

{

printf("Zhangsan told a %s.\n",a?"truth":"lie");

printf("Lisi told a %s.\n",b?"truch":"lie");

printf("Wangwu told a %s.\n",c?"truch":"lie");

}

}

*运行结果

Zhangsan told a lie (张三说假话)

Lisi told a truch. (李四说真话)

Wangwu told a lie. (王五说假话)

40.谁是窃贼

公安人员审问四名窃贼嫌疑犯。已知,这四人当中仅有一名是窃贼,还知道这四人中每人要么是诚实的,要么总是说谎的。在回答公安人员的问题中:

甲说:―乙没有偷,是丁偷的。‖

乙说:―我没有偷,是丙便的。‖

丙说:―甲没有偷,是乙偷的。‖

丁说:―我没有偷。‖

请根据这四人的答话判断谁是盗窃者。

*问题分析与算法设计

假设A、B、C、D分别代表四个人,变量的值为1代表该人是窃贼。

由题目已知:四人中仅有一名是窃贼,且这四个人中的每个人要么说真话,要么说假话,而由于甲、乙、丙三人都说了两句话:―X没偷,X偷了‖,故不论该人是否说谎,他提到的两人中必有一人是小偷。故在列条件表达式时,可以不关心谁说谎,谁说实话。这样,可以列出下列条件表达式:

甲说:‖乙没有偷,是丁偷的。‖ B+D=1

乙说:―我没有偷,是丙偷有。‖ B+C=1

丙说:―甲没有偷,是乙偷的。‖ A+B=1

丁说:―我没有偷。‖ A+B+C+D=1

其中丁只说了一句话,无法判定其真假,表达式反映了四人中仅有一名是窃贼的条件。 *程序说明与注释

#include<stdio.h>

int main()

{

int i,j,a[4];

for(i=0;i<4;i++) /*假定只有第i个人为窃贼*/

{

for(j=0;j<4;j++) /*将第i个人设置为1表示窃贼,其余为0*/

if(j==i)a[j]=1;

else a[j]=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. (乙为窃贼。)

41.拉丁方阵

构造 NXN 阶的拉丁方阵(2<=N<=9),使方阵中的每一行和每一列中数字1到N只出现一次。如N=4时:

1 2 3 4

2 3 4 1

3 4 1 2

4 1 2 3

*问题分析与算法设计

构造拉丁方阵的方法很多,这里给出最简单的一种方法。观察给出的例子,可以发现:若将每 一行中第一列的数字和最后一列的数字连起来构成一个环,则该环正好是由1到N顺序构成;对于第i行,这个环的开始数字为i。按照 此规律可以很容易的写出程序。下面给出构造6阶拉丁方阵的程序。

*程序说明与注释

#include<stdio.h>

#define N 6 /*确定N值*/

int main()

{

int i,j,k,t;

printf("The possble Latin Squares of order %d are:\n",N);

for(j=0;j<N;j++) /*构造N个不同的拉丁方阵*/

{

for(i=0;i<N;i++)

{

t=(i+j)%N; /*确定该拉丁方阵第i 行的第一个元素的值*/

for(k=0;k<N;k++) /*按照环的形式输出该行中的各个元素*/

printf("%d",(k+t)%N+1);

printf("\n");

}

printf("\n");

}

}

*运行结果

The possble Latin Squares of order 6 are:

1 2 3 4 5 6 2 3 4 5 6 1 3 4 5 6 1 2

2 3 4 5 6 1 3 4 5 6 1 2 4 5 6 1 2 3

3 4 5 6 1 2 4 5 6 1 2 3 5 6 1 2 3 4

4 5 6 1 2 3 5 6 1 2 3 4 6 1 2 3 4 5

5 6 1 2 3 4 6 1 2 3 4 5 1 2 3 4 5 6

6 1 2 3 4 5 1 2 3 4 5 6 2 3 4 5 6 1

4 5 6 1 2 3 5 6 1 2 3 4 6 1 2 3 4 5

5 6 1 2 3 4 6 1 2 3 4 5 1 2 3 4 5 6

6 1 2 3 4 5 1 2 3 4 5 6 2 3 4 5 6 1

1 2 3 4 5 6 2 3 4 5 6 1 3 4 5 6 1 2

2 3 4 5 6 1 3 4 5 6 1 2 4 5 6 1 2 3

3 4 5 6 1 2 4 5 6 1 2 3 5 6 1 2 3 4

42.填表格

将1、2、3、4、5和6 填入下表中,要使得每一列右边的数字比左边的数字大,每一行下面的数字比上面的数字大。按此要求,可有几种填写方法?

c语言趣味题

*问题分析与算法设计

按题目的要求进行分析,数字1一定是放在第一行第一列的格中,数字6一定是放在第二行第三列的格中。在实现时可用一个一维数组表示,前三个元素表示第一行,后三个元素表示第二行。先根据原题初始化数组,再根据题目中填 写数字的要求进行试探。

*程序说明与注释

#include<stdio.h>

int jud1(int s[]);

void print(int u[]);

int count; /*计数器*/

int main()

{

static int a[]={1,2,3,4,5,6}; /*初始化数组*/

printf("The possble table satisfied above conditions are:\n");

for(a[1]=a[0]+1;a[1]<=5;++a[1]) /*a[1]必须大于a[0]*/

for(a[2]=a[1]+1;a[2]<=5;++a[2]) /*a[2]必须大于a[1]*/

for(a[3]=a[0]+1;a[3]<=5;++a[3]) /*第二行的a[3]必须大于a[0]*/

for(a[4]=a[1]>a[3]?a[1]+1:a[3]+1;a[4]<=5;++a[4])

/*第二行的a[4]必须大于左侧a[3]和上边a[1]*/

if(jud1(a)) print(a); /*如果满足题意,打印结果*/

}

int jud1(int s[])

{

int i,l;

for(l=1;l<4;l++)

for(i=l+1;i<5;++i)

if(s[l]==s[i]) return 0; /*若数组中的数字有重复的,返回0*/

return 1; /*若数组中的数字没有重复的,返回1*/

}

void print(int u[])

{

int k;

printf("\nNo.:%d",++count);

for(k=0;k<6;k++)

if(k%3==0) /*输出数组的前三个元素作为第一行*/

printf("\n%d",u[k]);

else /*输出数组的后三个元素作为第二行*/

printf("%d",u[k]);

}

*运行结果

The possble table satisfied above conditions are:

No.1: No.2: No.3: No.4: No.5:

1 2 3 1 2 4 1 2 5 1 3 4 1 3 5

4 5 6 3 5 6 3 4 6 2 5 6 2 4 6

43.1~9分成1:2:3的三个3位数

将1到9 这九个数字分成三个3位数,分求第一个3位数,正好是第二个3位数的二倍,是第三个3位数的三倍。问应当怎样分法。

*问题分析与算法设计

问题中的三个数之间是有数学关系的,实际上只要确定第一个三位数就可以解决问题。

试探第一个三位数之后,计算出另外两个数,将其分别分解成三位数字,进行判断后确定所试探的数是否就是答案。

需要提醒的是:试探的初值可以是123,最大值是333。因为不可能超出该范围。 *程序与程序设计

#include<stdio.h>

int ok(int t,int *z);

int a[9];

int main()

{

int m,count=0;

for(m=123;m<=333;m++) /*试探可能的三位数*/

if(ok(m,a)&&ok(2*m,a+3)&&ok(3*m,a+6)) /*若满足题意*/

printf("No.%d: %d %d %d\n",++count,m,2*m,3*m); /*输出结果*/

}

int ok(int t,int *z) /*分解t的值,将其存入z指向的三个数组元素,若满足要求返回1*/ {

int *p1,*p2;

for(p1=z;p1<z+3;p1++)

{

*p1=t%10; /*分解整数*/

t/=10;

for(p2=a;p2<p1;p2++) /*查询分解出的数字是否已经出现过*/

if(*p1==0||*p2==*p1)return 0; /*若重复则返回*/

}

return 1; /*否则返回1*/

}

*运行结果

No.1:192 384 576

No.2:219 438 657

No.3:273 546 819

No.4:327 654 981

*思考题

求出所有可能的以下形式的算式,每个算式中有九个数位,正好用尽1到9这九个数字。

1)○○○+○○○=○○○ (共有168种可能的组合)

2)○×○○○○=○○○○ (共有2种可能的组合)

3)○○×○○○=○○○○ (共有7种可能的组合)

4)○×○○○=○○×○○○ (共有13种可能的组合)

5)○×○○○=○×○○○○ (共有28种可能的组合)

6)○○×○○=○×○○○○ (共有7种可能的组合)

7)○○×○○=○○×○○○ (共有11种可能的组合)

44.约瑟夫问题

这是17世纪的法国数学家加斯帕在《数目的游戏问题》中讲的一个故事:15个教徒和15 个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行直到仅余15个人为止。问怎样排法,才能使每次投入大海的都是非教徒。

*问题分析与算法设计

约瑟夫问题并不难,但求解的方法很多;题目的变化形式也很多。这里给出一种实现方法。 题目中30个人围成一圈,因而启发我们用一个循环的链来表示。可以使用结构数组来构成一个循环链。结构中有两个成员,其一为指向下一个人的指针,以构成环形的链;其二为该 人是否被扔下海的标记,为1表示还在船上。从第一个人开始对还未扔下海的人进行计数,每数到9时,将结构中的标记改为0,表示该人已被扔下海了。这样循环计数直到有15个人被扔下海为止。

*程序说明与注释

#include<stdio.h>

struct node

{

int nextp; /*指向下一个人的指针(下一个人的数组下标)*/

int no_out; /*是否被扔下海的标记。1:没有被扔下海。0:已被扔下海*/

}link[31]; /*30个人,0号元素没有使用*/

int main()

{

int i,j,k;

printf("The original circle is(+:pagendom,@:christian):\n");

for(i=1;i<=30;i++) /*初始化结构数组*/

{

link[i].nextp=i+1; /*指针指向下一个人(数组元素下标)*/

link[i].no_out=1; /*标志置为1,表示人都在船上*/

}

link[30].nextp=1; /*第30个人的指针指向第一个人以构成环*/

j=30; /*j:指向已经处理完毕的数组元素,从link[i]指向的人开始计数*/

for(i=0;i<15;i++) /*i:已扔下海的人数计数器*/

{

for(k=0;;) /*k:决定哪个人被扔下海的计数器*/

if(k<15)

{

j=link[j].nextp; /*修改指针,取下一个人*/

k+=link[j].no_out; /*进行计数。因已扔下海的人计标记为0*/

}

else break; /*计数到15则停止计数*/

link[j].no_out=0; /*将标记置 0,表示该人已被扔下海*/

}

for(i=1;i<=30;i++) /*输出结果*/

printf("%c",link[i].no_out? '@':'+'); /*+:被扔下海, @:在船上*/

printf("\n");

}

*运行结果

The original circle is(+:pagandom, @:christian):

+++@@+@+@@@+@+++@@+@@@+++@+@@+

(+"表示被扔下海海的非教徒 @:留在船上活命的教徒)

*思考题

有N个小孩围 成一圈并依次编号,教师指定从第M个小孩开始报数,报到第S个小孩即令其出列。然后从下一个孩子继续报数,数到第S个小孩又令其出列,如此直到所有的孩子都出列。求小孩出列的先后顺序。

45.邮票组合

某人有四张3分的邮票和三张5分的邮票,用这些邮票中的一张或若干张可以得到多少种不同的邮资?

*问题分析与算法设计

将问题进行数学分析,不同张数和面值的邮票组成的邮资可用下列公式计算:

S=3*i+5*j

其中i为3分邮柰的张数,j为5分的张数

按题目的要求,3分的邮票可以取0、1、2、3、4张,5分的邮票可以取0、1、2、3张。采用穷举方法进行组合,可以求出这些不同面值不同张数的邮标组合后的邮资。

*程序说明与注释

#include<stdio.h>

int a[27];

int main()

{

int i,j,k,s,n=0;

for(i=0;i<=4;i++) /*i:取三分邮票的张数*/

for(j=0;j<=3;j++) /*j:取5分邮票的张数*/

{

s=i*3+j*5; /*计算组成的邮票面值*/

for(k=0;a[k];k++) /*查找是否有相同的邮资*/

if(s==a[k])break;

if(!a[k]&&s) /*没有找到相同的邮资则满足要求存入数组*/

{

a[k]=s; n++;

}

}

printf("%d kinds:",n); /*输出结果*/

for(k=0;a[k];k++)

printf("%d ",a[k]);

printf("\n");

}

*运行结果

19 kinds: 5 10 15 3 8 13 18 6 11 16 21 9 14 19 24 12 17 22 27

46.和数能表示1~23的5个正整数

已知五个互不相同的正整数之和为23,且从这五个数中挑选若干个加起来可以表示从1到23之内的全部自然数。问这五个数是什么?

*问题分析与算法设计

从计算机程序设计的角度来说,可以用穷举法分解23,然后判断所分解的五个数是否可以表示1到23 之间的全部整数。

*程序说明与注释

#include<stdio.h>

int main()

{

int a,b,c,d,e,i,j,k,l,m,x,count=0,f=0; /*f:分解的5个数可以表示出1~23的标记*/ printf("There are following possble result:\n");

for(a=1;a<=23;a++) /*将23分解为a,b,c,d,e五个数*/

for(b=1+a;b<=23-a;b++)

for(c=1+b;c<=23-a-b;c++)

for(d=1+c;d<=23-a-b-c;d++)

{

f=1;

if((e=23-a-b-c-d)>d)

for(f=0,x=1;x<24&&!f;x++) /*判断5个数可否表示1~23*/

for(f=1,i=0;i<2&&f;i++) /*穷举5个数的全部取舍*/

for(j=0;j<2&&f;j++)

for(k=0;k<2&&f;k++)

for(l=0;l<2&&f;l++)

c语言趣味题

for(m=0;m<2&&f;m++)

if(x==a*i+b*j+c*k+d*l+e*m) f=0;

if(!f) printf("[%d]: %d %d %d %d %d\n",++count,a,b,c,d,e);

}

}

*运行结果

There are following possble result:

[1]: 1 2 3 5 12

[2]: 1 2 3 6 11

[3]: 1 2 3 7 10

[4]: 1 2 4 5 11

[5]: 1 2 4 6 10

[6]: 1 2 4 7 9

47.求π的近似值

请利用―正多边形逼近‖的方法求出π的近似值

*问题分析与算法设计

利用―正多边形逼近‖的方法求出π值在很早以前就存在,我们的先人祖冲之就是用这种方法在世界上第一个得到精确度达小数点后第6位的π值的。

利用圆内接正六边形边长等于半径的特点将边数翻番,作出正十二边形,求出边长,重复这一过程,就可获得所需精度的π的近似值。

假设单位圆内接多边形的边长为2b,边数为i,则边数加倍后新的正多边形的边长为:

周长为:

y=2 * i * x i:为加倍前的正多边形的边数

*程序说明与注释

#include<stdio.h>

#include<math.h>

int main()

{

double e=0.1,b=0.5,c,d;

long int i; /*i: 正多边形边数*/

for(i=6;;i*=2) /*正多边形边数加倍*/

{

d=1.0-sqrt(1.0-b*b); /*计算圆内接正多边形的边长*/

b=0.5*sqrt(b*b+d*d);

if(2*i*b-i*e<1e-15) break; /*精度达1e-15则停止计算*/

e=b; /*保存本次正多边形的边长作为下一次精度控制的依据*/

}

printf("pai=%.15lf\n",2*i*b); /*输出π值和正多边形的边数*/

printf("The number of edges of required polygon:%ld\n",i);

}

*运行结果

pai=3.141592653589794

The number of edges of required polygon:100663296

*思考题

请用外切正多边形逼近的方法求π的近似值。

48.求π的近似值(2)

利用随机数法求π的近似值

*问题分析与算法设计

随机数法求π的近似值的思路:在一个单位边长的正方形中,以边长为半径,以一个顶点为圆心,在政权方形上作四分之一圆。随机的向正方形内扔点,若落入四分之一圆内则计数。重复向正方形内扔足够多的点,将落入四分之一圆内的计数除以总的点数,其值就是π值四分之一的近似值。

按此方法可直接进行编程,注意:本方法求出的π值只有统计次数足够多时才可能准确。 *程序说明与注释

#include<time.h>

#include<stdlib.h>

#include<stdio.h>

#define N 30000

int main()

{

float x,y;

int c=0,d=0;

randomize();

while(c++<=N)

{

x=random(101); /*x:坐标。产生0到100之间共101个的随机数*/

y=random(101); /*y:坐标。产生0到100之间共101个的随机数*/

if(x*x+y*y<=10000) /*利用圆方程判断点是否落在圆内*/

d++;

}

printf(" pi=%f\n",4. *d/N); /*输出求出的π值*/

}

*运行结果

多次运行程序,可能得到多个不同的对口果,这是因为采用的是统计规律求出的近似值,只有当统计的次数足够大时,才可能逼近π值。运行四次,可能的结果是:

3.122267

3.139733

3.133733

49.奇数平方的一个有趣性质

编程验证―大于1000的奇数其平方与1的差是8的倍数‖。

*问题分析与算法设计

本题是一个很容易证明的数学定理,我们可以编写程序验证它。

题目中给出的处理过程很清楚,算法不需要特殊设计。可以按照题目的叙述直接进行验证(程序中仅验证到3000)。

*程序说明与注释

#include<stdio.h>

int main()

{

long int a;

for(a=1001;a<=3000;a+=2)

{

printf("%ld:",a); /*输出奇数本身*/

printf("(%ld*%ld-1)/8",a,a); /*输出(奇数的平方减1)/8*/

printf("=%ld",(a*a-1)/8); /*输出被8除后的商*/

printf("+%ld\n",(a*a-1)%8); /*输出被8除后的余数*/

}

}

50.角谷猜想

日本一位中学生发现一个奇妙的―定理‖,请角谷教授证明,而教授无能为力,于是产生角谷猜想。猜想的内容是:任给一个自然数,若为偶数除以2,若为奇数则乘3加1,得到一个新的自然数后按照上面的法则继续演算,若干次后得到的结果必然为1。请编程验证。

*问题分析与算法设计

本题是一个沿未获得一般证明的猜想,但屡试不爽,可以用程序验证。

题目中给出的处理过程很清楚,算法不需特殊设计,可按照题目的叙述直接进行证。 *程序说明与注释

#include<stdio.h>

int main()

{

int n,count=0;

printf("Please enter number:");

scanf("%d",&n); /*输入任一整数*/

do{

if(n%2)

{

n=n*3+1; /*若为奇数,n乘3加1*/

printf("[%d]:%d*3+1=%d\n",++count,(n-1)/3,n);

}

else

{

n/=2; /*若为偶数n除以2*/

printf("[%d]: %d/2=%d\n",++count,2*n,n);

}

}while(n!=1); /*n不等于1则继续以上过程*/

}

51.四方定理

数论中著名的―四方定理‖讲的是:所有自然数至多只要用四个数的平方和就可以表示。 请编程证此定理。

*问题分析与算法设计

本题是一个定理,我们不去证明它而是编程序验证。

对四个变量采用试探的方法进行计算,满足要求时输出计算结果。

*程序说明与注释

#include<stdio.h>

#include<stdlib.h>

int main()

{

int number,i,j,k,l;

printf("Please enter a number=");

scanf("%d",&number); /*输入整数*/

for(i=1;i<number/2;i++) /*试探法。试探i,j,k,k的不同值*/

for(j=0;j<=i;j++)

for(k=0;k<=j;k++)

for(l=0;l<=k;l++)

if(number==i*i+j*j+k*k+l*l) /*若满足定理要求则输出结果*/

{

printf(" %d=%d*%d+%d*%d+%d*%d+%d*%d\n",number,i,i,j,j,k,k,l,l); exit(0);

}

}

*运行结果

1) Please enter a number = 110

110=7*7+6*6+4*4+3*3

2) Please enter a number = 211

211=8*8+7*7+7*7+7*7

3) Please enter a number = 99

99=7*7+5*5+4*4+3*3

52.常胜将军

现有21根火柴,两人轮流取,每人每次可以取走1至4根,不可多取,也不能不取,谁取最后一楰火柴谁输。请编写一个程序进行人机对弈,要求人先取,计算机后取;计算机一方为―常胜将军‖。

*问题分析与算法设计

在计算机后走的情况下,要想使计算机成为―常胜将军‖,必须找出取 关键。根据本题的要求枷以总结出,后走一方取子的数量与对方刚才一步取子的数量之和等于,就可以保证最后一个子是留给先取子的那个人的。

据此分析进行算法设计就是很简单的工作,编程实现也十分容易。

*程序说明与注释

#include<stdio.h>

int main()

{

int a=21,i;

printf("Game begin:\n");

while(a>0)

{

do{

printf("How many stick do you wish to take(1~%d)?",a>4?4:a);

scanf("%d",&i);

}while(i>4||i<1||i>a); /*接收正在确的输入*/

if(a-i>0) printf(" %d stick left in the pile.\n",a-i);

if((a-i)<=0)

{

printf(" You have taken the last stick.\n");

printf(" * * * You lose! \nGame Over.\n"); /*输出取胜标记*/

break;

}

else

printf(" Compute take %d stick.\n",5-i); /*输出计算机取的子数*/

a-=5;

printf(" %d stick left in the pile.\n",a);

}

}

*思考题

改变题目中火柴的数量(如为22根),则后走的一方就不一定能够保持常胜了,很可能改变成―常败‖。此时后走一方的胜负就与火柴的初始数量和每次允许取的火柴数量的最大值有直接关系,请编写程序解决这一问题。

53.兎子产子

从前有一对长寿兎子,它们每一个月生一对兎子,新生的小兎子两个月就长大了,在第二个月的月底开始生它们的下一代小兎子,这样一代一代生下去,求解兎子增长数量的数列。

*问题分析与算法设计

问题可以抽象成下列数学公式:

Un=Un-1+Un-2

其中:

n是项数(n>=3)。它就是著名的菲波那奇数列,该数列的前几为:1,1,2,3,5,8,13,21…

菲波那奇数列在程序中可以用多种方法进行处理。按照其通项递推公式利用最基本的循环控制就可以实现题目的要求。

*程序说明与注释

#include<stdio.h>

int main()

{

int n,i,un1,un2,un;

for(n=2;n<3;)

{

printf("Please enter required number of generation:");

scanf("%d",&n);

if(n<3) printf("\n Enter error!\n"); /*控制输入正确的N值*/

}

un=un2=1;

printf("The repid increase of rabbits in first %d generation is as felow:\n",n); printf("l\tl\t");

for(i=3;i<=n;i++)

{

un1=un2;

un2=un;

un=un1+un2; /*利用通项公式求解N项的值*/

printf(i%10?"%d\t":"%d\n",un);

}

printf("\n");

}

*运行结果

Please enter required number of generation: 20

The repid increase of rabbits in first 20 generation is as felow:

1 1 2 3 5 8 13 21 34 55

89 144 233 377 610 987 1597 2584 4181 6765

更多相关推荐:
语言的名言

思想是不出声的语言中国现代作家文学研究家钱钟书围城辞达则止不贵多言南宋哲学家教育家诗人朱熹时间是大公无私的语言俄罗斯作家尤邦达列夫炼辞得奇句炼意得余味北宋哲学家易学家邵雍论诗吟语言名言宋邵雍论诗吟这两句大意是锤...

语言积累名言名句类

语言积累名言名句类1冬天麦盖三层被来年枕着馒头睡2瑞雪兆丰年这并不是迷信有着充分的科学根据3万事俱备只欠东风4不要想着远在下面的岩石而要着眼于那最初的一小步走了这一小步再走下一步直到抵达我所要到的地方5不论未来...

语言积累名言名句类

语言积累名言名句类七上1冬天麦盖三层被来年枕着馒头睡2瑞雪兆丰年这并不是迷信有着充分的科学根据3万事俱备只欠东风4不要想着远在下面的岩石而要着眼于那最初的一小步走了这一小步再走下一步直到抵达我所要到的地方5不论...

经典名言语录精选100句

公务员面试经典名言语录精选100句在公务员面试中好的语言亮点是取得高分的亮点之一结合公务员面试考查范围整理经典名言警句以供在面试中参考之用民本篇1民生在勤勤则不匮左传2民惟邦本本固邦宁尚书3圣人无常心以百姓心为...

关于行动胜于言语的名言1

关于行动的名言名句行动胜于语言admin20xx028浏览1806更多书中自有颜如玉书中自有黄金屋这是人们对读书的高度评价但人们对行动的评价更是超越书本读万卷书不如行万里路可见行动在生活中的重要之处Amanli...

读书名人名言大全

读书名人名言大全1学就像一只钻头去开掘知识的深井问就像一把钥匙去启开疑团的大门作者新格言2凡读无益之书皆是玩物丧志作者清王豫3读书对于智慧就象体操对于身体一样作者英国谚语4读书不知味不如束高阁蠢鱼尔何如终日食糟...

关于信仰的名言警句格言语录

关于信仰的名言警句格言语录享有特权而无力量的人是废物受过教育而无影响的人是一堆一文不值的垃圾有些人在知识道德宗教信仰方面受过教养但没有成为社会上行善的积极力量这些人就对不起为培育和供养他们而花费的代价如果他们也...

名言对比翻译

ActivityistheonlyroadtoknowledgeGeorgeBernardShawBritishdramatist行动是通往知识的唯一道路英国剧作家肖伯纳GAfreemanobtainsknow...

公务员面试辅导语言表达系列一:用名言警句让你的面试语言闪闪发光

黑龙江中公教育国家公务员考试的笔试已经过去了两周考生们的面试备考已经逐步进入正轨了中公教育专家结合自己的实践经验撰写公务员面试辅导语言表达系列稿件提高考生的实战能力中公教育专家在实际带队辅导考生的过程中感受到学...

中国名言西语版

有其父必有其子Talpadrecualhijo眼不见心不烦Ojosquenovencoraznquenosiente天道酬勤QuienmadrugaDiosleayuda一寸光阴一寸金Eltiempoesdin...

德语名言警句

1玩人丧德玩物丧志尚书仲虺之诰WeranderezumNarrenhltverliertseineTugendwersichmitunntzenDingenbeschftigtverliertseineZiel...

德语62格言

1JedenTaggibt39sdieMoeglichkeiteinesWunders每一天都有发生奇迹的可能2JederMenschistgeheimnisvollDuhastgarkeineAhnungwi...

语言名言(33篇)