x=x+1'构造累乘的数据
f=f*x'累乘运算
Loop
Print"f=";f
EndSub
注意:
这里的n不能太大,否则会出现“溢出”错误。
因为累积器f的数据类型为整型,能存放的最大整数为32767,如果要计算的n较大时,可将f的数据类型改为长整型、单精度型或双精度型。
上例中,若问题是1+2+3+…+n,只需要将f初始值设为0,将f=f*x改为f=f+x。
以下同类题目与上例算法相同,对累加的数x进行适当变换,注意数据类型:
1.
(累加为:
f=f+1/x)或(将x变换为:
i=i+1:
x=1/i)
2.1-2+3-…-100(累加为:
f=f+x*(-1)^(n-1))
3.1!
+2!
+3!
+...+n!
(增加累加运算的语句s=s+f)
4.
(累加为:
f=f+1/(x*(x+1))
5.a+aa+aaa+…+aa…aa(累加:
f=f+x^n)或(将x变换为:
x=x*x)
n个a
6.用
公式求π的近似值,直到最后一项的绝对值小于10-6为止(结合1,2两个问题,构造运算表达式,主要循环控制条件)
对累加和累乘的题目,总结如下:
(1)用一个或若干个表达式(x=x+1)运算产生要累乘或累加的每一项;
(2)用一个表达式,如f=f*x(f=f+x),将产生的项累加或累乘起来。
(3)依据题目命题,结合前面两项,构造合适的循环语句和条件。
通过本节分析举例,对同类问题可以达到举一反三的效果。
5.2.2计数与统计
若求解问题的结果是计数或统计,通过分析后,其本质是计数(简单累加:
n=n+1)、统计(分类计数、累加s=s+x或求均值p=s/n等)。
程序设计的基本思路是:
首先,确定每次计数或统计的处理对象是什么;其次,这些对象进行处理(统计或计数)依据是什么,有哪些处理条件;再次,将处理过程其表示成有规律的形式,构造统计或计数运算的表达式,形成每次重复操作的内容(循环体);最后,确定实现重复运算的控制方法(循环控制)。
例5-2从键盘上输入若干个数,求其平均值。
分析:
求若干个数的平均值,需要对数据累加求和,并对累加数据进行计数,让后计算得到平均值,问题的本质是累加(s=s+x),计数(n=n+1)。
基本思路和求解基本方法:
(1)设统计的数为x,通过键盘输入;
(2)处理要求是对每个数据x需要进行累加,同时进行计数;
(3)处理过程可以表示为(s=s+x:
n=n+1);
(4)确定控制循环执行的条件。
由于要进行累加与统计数据个数,需要设置两个变量sum、n,可以分别称它们为累加器变量sum和计数器变量n,与上题不同的是累加器变量中累加的是从键盘输入的数据。
它们的初值一般为0。
对于不固定个数的数求和,其累加、计数的次数也不固定,应采用Do循环。
为了使循环能够结束,需设定一个结束标志,本题可设置-9999(结束标志应选择远离有效数据为宜)做结束标志。
代码如下:
PrivateSubCommand1_Click()
Dimsum!
n%,x!
aver!
sum=0'累加器初值置0
n=0'计数器初值置0
x=Val(InputBox("请输入:
"))'输入第1个数
DoWhilex<>-9999
sum=sum+x
n=n+1
x=Val(InputBox("请输入:
"))'输入下1个数
Loop
aver=sum/n
MsgBox"共输入"&n&"个数,平均值为:
"&aver
EndSub
从分析可以看出循环体外的InputBox(),用来输入求和的第1个数,目的是为进入循环;循环体内InputBox()函数用来输入除第1个数以外的其他数及结束标志-9999,目的是维持循环并最后能够结束循环。
如果在本题中第1次输入数据时就输入-9999,会出现错误,请读者思考出错的原因?
如果将程序修改成:
Dimsum!
n%,x!
aver!
sum=0
n=0
DoWhilex<>-9999
x=Val(InputBox("请输入:
"))
sum=sum+x
n=n+1
Loop
aver=sum/n
MsgBox"这些数的平均值为:
"&aver
程序又会出现什么问题呢?
请大家试一试。
本例学习的重点:
在循环次数未知的情况下使用输入循环标志结束循环的方法。
例5-3输入多名学生的一门课程的考试成绩(假设为整数),统计各分数段学生人数。
在计算机数据处理中,如果需要多个计数器,可以考虑使用一维数组,利用数组元素充当计数器进行多项计数.
分析:
学生人数无法预先知道,因此应采用动态数组存储学生成绩,输入数据时采用文本框输入,便于数据的编辑。
本例是要统计各分数段(11段)的人数,所以要使用的计数器变量不止一个(11个),可以考虑用一维数组的数组元素作为计数器,通过巧妙的使用进行计数和批量处理。
“统计”按钮用于将录入的数据保存在一维数组中,并完成统计处理和结果输出。
程序运行界面如图5-2。
PrivateSubCommand1_Click()
Dima$()
Dimx(0To10)AsInteger
'数组元素充当计数器,保存统计结果
a=Split(Text1,",")
Fori=0ToUBound(a)
If(a(i)<=100Anda(i)>0)Then
k=a(i)\10
x(k)=x(k)+1
EndIf
Nexti
Print"统计结果如下:
"
Print"100分的有:
"&x(10)&"人"
Fori=9To0Step-1
Printi*10&"分-";i*10+9&"分有:
"&x(i)&"人"
Nexti
EndSub
PrivateSubCommand2_Click()
End
EndSub
请反复录入数据试运行程序,体会成绩分段统计技巧。
例5-4输入一串字符,统计各字母出现的次数(不区分大小写),并输出统计结果,如图5-3。
分析:
统计26个字母出现的次数,需要26个计数器,可以声明一个具有26个元素的一维数组。
算法如下:
(1)用取子串函数Mid(Text1,i,1)从Text1中取出每一个字符,并转换成大写字母;
(2)将A~Z之间的大写字母用Asc()函数转换成ASCII码值,再根据ASCII码值为相应的数组元素计数。
代码如下:
PrivateSubCommand1_Click()
Dima%(65To90),cAsString*1
le=Len(Text1)
Fori=1Tole
c=UCase(Mid(Text1,i,1))'分离出的字母转换成大写字母,方便统计
Ifc>="A"Andc<="Z"Then
j=Asc(c)
a(j)=a(j)+1
EndIf
Nexti
Forj=65To90'输出字母及其出现的次数
Ifa(j)>0ThenPicture1.Print"";Chr(j);"=";a(j);"";
Nextj
EndSub
5.2.3计算定积分
例5-5求
求一个函数f(x)在[a,b]上的定积分
,其几何意义是求f(x)曲线和直线x=a,y=0,x=b所围成的曲边图形的面积,如图5-4所示。
问题分析:
为了近似求出此面积,可将[a,b]区间分成若干个小区间,每个区间的宽度为h=(b-a)/n,n为区间个数。
近似求出每个小的曲边图形的面积,然后将n个小面积加起来,就近似求得总面积。
即定积分的近似值,当n愈大,近似程度愈高。
近似求出小曲边图形面积的方法,常用的有以下三种:
①用小矩形代替小曲边图形,求出各小矩形的面积,然后累加。
②用小梯形代替小曲边图形
③在小区间范围内,用一条直线代替该区间内的抛物线,然后求出该直线与x=a+(i-1)h,y=0,x=a+ih形成的小曲边图形面积
(1)矩形法求面积
矩形法求积分值是将积分区间[a,b]n等分,小区间的宽度为
,第i块小矩形的面积是:
。
程序设计的基本思路:
(1)设置区间[a,b],确定区间等分n的值,计算区间宽度h,
(2)第1个区间矩形坐标为x,则x=a,其对应的函数值f(x)为矩形的一边长度;
(3)计算区间矩形的长度f(x),则区间矩形面积为si=f(x)*h;
(4)进行一个矩形面积累加:
s=s+si;
(5)在前一x的基础上,得到下一矩形坐标x=x+h;
(6)通过
(2),(3),(4),实现一个矩形面积计算和累加,通过n次累加,得到积分值。
程序流程图如图5-5所示,代码如下:
PrivateSubCommand1_Click()
Dims!
si!
h!
x!
a!
b!
n%
a=0:
b=1'设置区间
n=100'设置区间等分数
h=(b-a)/n'计算宽度为h
x=a'设置第1个区间矩形坐标
s=0
Fori=1Ton
si=Sin(x)*h'计算矩形面积
s=s+si'面积累加
x=x+h'生成下一个x
Nexti
Print"用矩形法求得的定积分为:
";s
EndSub
(2)梯形法求面积
梯形法积分的思路是:
将积分区间[a,b]n等分,小区间的长度为
,第i块小梯形的面积是:
方法1:
PrivateSubCommand2_Click()
Dims!
si!
h!
a!
b!
n%
a=0:
b=1:
n=100
h=(b-a)/n
s=0
Fori=1Ton
si=(Sin((i-1)*h)+Sin(i*h))*h/2
s=s+si
Nexti
Print"用梯形法1求得的定积分为:
";s
EndSub
方法2:
对于梯形法来说,上一个小梯形的下底就是下一个梯形的上底,因此,把求面积的分析转化为求小区间端点函数值的问题,计算公式如下:
PrivateSubCommand3_Click()
Dims!
si!
h!
x!
a!
b!
n%
a=0:
b=1:
n=100
h=(b-a)/n
s=(Sin(a)+Sin(b))/2
Fori=1Ton-1
x=a+i*h
s=s+Sin(x)
Nexti
si=s*h
Print"用梯形法2求得的定积分为:
";si
EndSub
此问题参加运算的数据先通过多个步骤运算处理获得,然后进行面积累加计算。
因此,求定积分的值算法在本质上累加问题模型,只是运算步骤和过程较多而已。
5.3穷举法求解问题
穷举法也叫枚举法或列举法,基本思想是根据提出的问题,列举出所有的可能情况,并依据问题中给定的条件检验哪些情况是想要的(符合要求的),并将符合要求的情况输出。
这种方法常用于解决“是否存在”或“有多少种可能”等类型的问题。
如判断质数、不定方程求解等。
5.3.1最大公约数与最小公倍数
例5-6给定任意两个整数m和n,求最大公约数和最小公倍数。
分析:
若两个整数为m和n,假设m>n,设x为最小公倍数,则可能为最小公倍数x的取值范围为[m,m*n],可用穷举法的办法求解。
基本思路:
(1)列举出可能是m、n最小公倍数x的情况,则x的取值情况为[m,m*n];
(2)依据公倍数的定义,判断x的每个取值否满足条件:
x能同时被m和n整除;
(3)若能整除,x取值为最小公倍数,求解结束;
(4)通过循环操作实现穷举每个x取值情况;
基本算法是:
(1)对x从m开始的每一个可能的取值,判断能否同时被m、n整除(即是否是公倍数);
(2)若是,x必定是m和n的最小的公倍数,程序运行结束;
(3)如果不是,则判断下一个x;
(4)依次类推,直到x的取值为m*n为止。
最大公约数算法与最小公倍数类似,设y为最大公约数,y的范围是[1,n],程序实现时,y的取值从n开始,判断过程与求最小公倍数类似,流程图如图5-6所示,代码如下:
PrivateSubCommand1_Click()
Dimm%,n%
m=Val(InputBox("请输入第1个数m:
"))
n=Val(InputBox("请输入第2个数n:
"))
Ifmm=n:
n=t'满足m>n
Forx=mTom*n'最小公倍数,x[m,m*n]
IfxModm=0AndxModn=0Then
Print"最小公倍数为:
";x
ExitFor'结束循环
EndIf
Nextx
Fory=nTo1Step-1'y取值范围为n~1
IfmMody=0AndnMody=0Then
Print"最大公约数为:
";y
ExitFor'结束循环
EndIf
Nexty
EndSub
这种方法效率较低,求最大公约数可采用经典的“辗转相除法”,并在求出最大公约数后,最小公倍数就等于两个原数的乘积除以最大公约数。
算法描述如下:
(1)将m除以n得余数r;
(2)若r=0,则n为求得的最大公约数,循环结束;若r≠0,则执行(3);
(3)将n赋给m,将r赋给n,再重执行
(1)、
(2)步。
代码如下:
PrivateSubCommand1_Click()
Dimm%,n%,r%
m=Val(InputBox("请输入第1个数m:
"))
n=Val(InputBox("请输入第2个数n:
"))
mn=m*n
r=mModn
DoWhiler<>0
m=n
n=r
r=mModn
Loop
MsgBox"两个数的最大公约数为"&n&",最小公倍数为"&mn/n
EndSub
本例因为在循环过程中由于改变了m、n的值,所以先将m*n的值放入变量mn中。
读者可以比较一下两种算法的循环次数。
穷举法是基于计算机特点而进行解题的思维方法,一般是根据问题中的部分条件(约束条件)将所有可能解的情况列举出来,然后通过一一验证是否符合整个问题的求解要求,从而得到问题的解。
穷举法一般解题模式为:
(1)问题解的可能搜索的范围:
用循环或循环嵌套结构实现;此问题用计算机进行求解时一般使用穷举验证的方法进行。
(2)写出符合问题解的条件;
(3)能使程序优化的语句,以便缩小搜索范围,减少程序运行时间。
5.3.2质数
质数也叫素数,是指只能被1和它本身整除的自然数。
最小的质数是2。
例5-7从键盘输入一个数m,判断是否为质数。
分析:
判断一个数m是否为质数的方法很多,最基本的是从质数的定义来求解,设x为可能整除m的数,则x取值范围为[2,m-1],可用穷举法求解。
基本思路:
(1)列举出可能整除m的数x的情况,则x取值情况为[2,m-1];
(2)判断x的每个取值情况:
x是否能整除m;
(3)若能整除,则m不是质数,不再进行判断;
(4)若不能能整除,则需要进行下一个x判断;
(5)通过循环操作实现穷举每个x取值情况。
(6)结果判读,在循环处理过程中,若都不能整除m,则m为素数,只要其中有一个数能整除m,则m就不是质数。
基本算法:
(1)输入m,设置标志flag=True,默认m为质数;
(2)x从2开始取值,判断x能否整除m;
(3)若整除,则m不是质数,设置标志位false,结束判断;
(4)若不整除,则判断下一个x,即x=x+1;
(5)依次类推,直到x的取值为m-1为止。
(6)依据flag标志,若flag为True,则m为质数,否则m不是质数。
流程图如图5-7所示,程序代码如下:
PrivateSubCommand1_Click()
Dimm%,i%,flagAsBoolean
m=Val(InputBox("请输入要判断的整数m"))
flag=True'先假设m是质数数
For