在编程中经常遇到需要多次规律相同的重复处理,这就是循环问题。Turbo Pascal采用不同的循环方式来实现,常用的环循有三种: for、repeat、while.
第一节 for 循环
for循环是一种自动计数型循环。
[例3.1] 试打印出1~20的自然数。
解:① 用a代表1~20各数,同时也用a兼作计数,以控制循环次数;
② 让a从1开始;
③ 输出a;
④ a自动计数(加1),如果未超越所规定的循环范围则重复步骤③,否则结束循环。
Pascal程序:
Program Exam12;
Var a: byte;
Begin
for a:=1 to 20 do
Writeln (a);
Readln
End.
程序中 for a:=1 to 20 do Writeln (a); 是for循环语句。
for 循环语句有两种格式:
(1) for 循环变量:=初值 To 终值 do 语句;
(2) for 循环变量:=初值 downto 终值 do 语句;
第(1)种格式的初值小于等于终值,循环变量值按自动加1递增变化;
第(2)种格式的初值大于或等于终值,循环变量值按自动减1递减变化。for 循环是 (以递增1或以递减1) 计数型循环。
比如: 若将[例3.1]程序改为倒计数(递减)循环,则输出20~1的自然数数:
Program Exam31;
Var a: byte;
Begin
for a:=20 downto 1 do
Writeln(a) ;
Readln
End.
[例3.2]打印出30至60的偶数。]
解:
方法一:
①设a表示30至60的所有的数,可用for循环列出;
②用式子 a mod 2=0 筛选出其中的偶数并输出。
Pascal程序:
Program ex32;
Var a : integer;
Begin
For a := 30 to 60 do
If (a mod 2=0) then writeln(a);
Readln;
End.
在这个程序中,for循环后的循环语句是一个条件分支语句。
方法二:我们知道,在式子a=2*n中,若n取自然数1、2、3、…,时,则a依次得到偶数2、4、6、…。因此要想得到30至60的偶数,就可以让上面式子中的n取15至30的自然数就可以了。所以本题还可以按以下步骤处理:
①设n表示15至30的所有自然数,可用for循环列出;
②用式子 a := 2*n 求出其中的偶数;
③将结果输出至屏幕。
Pascal程序:
Program ex32;
Begin
For n := 15 to 30 do
Begin
a := 2*n;
Writeln(a);
End;
Readln;
End.
[例3.3]自然数求和:编一个程序,求从1至100的自然数的和。
解:① 令S=0;
② 令a表示1至100的自然数,用循环列出;
③ 将这些自然数用公式S:=S+a 逐一累加到S中去;
④ 循环结束后,S即为1至100的自然数的和,输出即可。
Pascal程序:
Program ex33;
var s,a : integer;
Begin
S := 0;
For a := 1 to 100 do
S := S+a;
Writeln(‘S=’,S);
Readln;
End.
[例3.4]一个两位数x,将它的个位数字与十位数字对调后得到一个新数y,此时y恰好比x大36,请编程求出所有这样的两位数。
解:① 用for循环列举出所有的两位数,x为循环变量;
② 用公式a:= x div 10分离出x的十位数字;
③ 用公式b:= x mod 10分离出x的个位数字;
④ 用公式y:= b*10+a合成新数y;
⑤ 用式子y-x=36筛选出符合条件的数x并输出。
Pascal程序:
Program ex34;
Begin
For x := 10 to 99 do
Begin
a := x div 10;
b := x mod 10;
y := b*10+a;
if y-x=36 then writeln(x);
End;
Readln;
End.
[例3.5] 把整数3025从中剪开分为30和25两个数,此时再将这两数之和平方,(30+25)2=3025计算结果又等于原数。求所有符合这样条件的四位数。
解:设符合条件的四位数为N,它应当是一个完全平方数,用(a*a)表示。
① 为了确保N=(a*a)在四位数(1000~9999)范围内,可确定a在32~99循环;
② 计算N=a*a;将四位数N拆分为两个数n1和n2;
③ 若满足条件(n1+n2)*(n1+n2)=N 就输出 N 。
Pascal程序:
Program Exam35;
Var N,a, x,n1,n2: Integer;
Begin
for a:=32 to 99 do
begin
N:=a*a;
n1:= N div 100; {拆取四位数的前两位数}
n2:= N-n1*100; {拆取四位数的后两位数}
X:=n1+n2;
if x*x=N then writeln (N);
end;
Readln
End.
[例3.6]用“*”号打印出如下的长方形图案。
*********
*********
*********
*********
解:① 上面给出的图例共有4行,我们可以用一个循环控制行的变化;
② 在每行中又有9列,我们可以在前面控制行的循环中再套一个循环来控制列的变化。
Pascal程序:
Program ex36;
Begin
For a := 1 to 4 do {外循环控制行的变化}
Begin
For b := 1 to 9 do {内循环控制列的变化}
write(‘*’);
Writeln; {输出一行的“*”后换行}
End;
Readln;
End.
程序中的循环对于a的每个值都包含着一个b=(1~9)次的内循环。外循环for a 将内循环for b 包含在里面,称为for循环的嵌套。嵌套形式如:
for a:=n1 to n2 do
for b:=m1 to m2 do 循环体语句;
[例3.7] 打印出九九乘法表:
解:设a为被乘数,范围为1~9;b为乘数,范围为1~a;乘式为a*b=(a,b的乘积),则
a=1: b=1~a 1*1=1
a=2: b=1~a 2*1=2 2*2=4
a=3: b=1~a 3*1=3 3*2=6 3*3=9
a=4: b=1~a 4*1=4 4*2=8 4*3=13 4*4=16
: :
a=9 b=1~a 9*1=9 9*2=18 … 9*9=81
⑴从上面分解的横行中看到共有9行,这里的“行”数变化与a的变化从1~9相同,可用a控制“行”的循环;
⑵每“行”里面相乘的次数与b的范围相关,由b控制每“行”里面的“内部”循环;
⑶内循环被包含在最里层,执行完每“行”的内部循环,就到下一“行”去执行新“行”里面的循环,每“行”都拥有形式相同的( b=1~a )内循环。
即每到一“行”都要执行该“行”的内循环。这里所指的“行”可以理解成抽象的行,不一定是实际上具体对应的行,可以是一个处理“块”。
Pascal程序:
Program Exam37;
Var a,b: byte;
Begin
for a:=1 to 9 do {外循环 }
begin
for b:=1 to a do {内循环 }
write(a,’* ’,b,’= ’,a*b,’ ’:3);
writeln
end;
Readln
End.
根据这种格式还可以实现多层循环嵌套,例如:
for a:=n1 to n2 do
for b:=m1 to m2 do
for c:=k1 to k2 do 循环体语句;
[例3.8]从七张扑克牌中任取三张,有几种组合方法?请编程输出所有组合形式。
解:设每次取出三张分别为a,b,c。用三重循环分别从1~7的范围里取值;为了排除取到重号,用(a-b)*(b-c)*(a-c) < >0进行判断。
Pascal程序:
program Exam38;
const n=7;
var a,b,c,t: integer;
Begin
t:=0;
for a:=1 to n do
for b:=1 to n do
for c:=1 to n do
if (a-b) * (b-c) * (a-c) < >0 then
Begin
inc (t);
writeln (a:3, b:3, c:3)
End;
writeln ( total:, t :5);
readln
End.
[例3.9] 数学上把除了1和它本身,没有别的数能够整除它的自然数叫做素数(或质数)。现在由键盘输入一个自然数N,编程判断N是否是素数,是则输出“Yes”,否则输出“No”。
解:根据定义,对于给定的自然数N,只需判断除1和它本身外,还有没有第三个自然数即可。
① 令K从1循环至N;
② 根据N mod K是否为0可统计K的约数的个数;
③ 若N的约数的个数超过2个,则判定N不是素数。
Pascal程序:
Program Exam39;
Var n,m,k,t: integer;
Begin
write(‘N=’);
ReadLn(N);
t:=0;
for k:=1 to N do {外循环 }
if N mod k=0 then t := t+1; {如果N是奇数 }
if t>2 then writeln(‘No’)
else writeln(‘Yes’);
Readln;
End.
程序中的变量yse为布尔(或逻辑)类型(Boolean)。布尔值只有两个:
True(真) False(假)
布尔值与条件判断结果为真(条件成立)或为假(条件不成立)的作用相同,常用于条件语句和循环语句中。
上面程序中用 if yes and (t mod 7=0) then writeln;实现每行打印七个素数换行,程序中布尔变量yes为真,在逻辑上表示是素数;关系式(t mod 7=0) 的值为真时,表示该行输出素数巳是7个;用and将这两个“条件”连起来是作一种布尔(逻辑)运算。
Pascal 共有四种逻辑运算符:
① and (与) 两条件都为True时,其结果值为True;否则为False;
② or (或) 两条件中只要有一个为True ;其结果值为True;否则为False;
③ xor (异或) 两条件的逻辑值不相同时,其结果值为True;否则为False;
④ not (非) 条件为True时,其结果值为False;否则为True;(取反)
习题3.1:
1.打印出1至20的平方数表。
2.打印出100至200之间的奇数。
3. 鸡兔同笼(用for循环程序完成)
4.一辆快车和一辆慢车开往同一地点,快车票价为18元,慢车票价为13. 5元,共售出400张,共计5940元,求快车票和慢车票各多少张?.
5.求出能被5整除的所有四位数的和。
6.在下面式子中的二个□内填入一个合适的同样的数字,使等式成立。
□3*6528=3□*8256
7.有一个三位数,它的各位数字之和的11倍恰好等于它自身,请编程求出这个三位数。
8.在自然数中,如果一个三位数等于自身各位数字之立方和,则这个三位数就称为是水仙花数。如:153=13+53+33,所以153是一个水仙花数。求所有的水仙花数。
9.编程序打印出下列图案:
平行四边形 等腰三解形 菱形
****** * *
****** *** ***
****** ***** *****
****** ******* ***
****** ********* *
10.编程打印出如下图案:
1
222
33333
4444444
555555555
11.有三种明信片:第一种每套一张,售价2元;第二种每套一张,售价4元; 第三种每套9张,售价2元。现用100元钱要买100张明信片,要求每种明信片至少要买一套,问三种明信片应各买几套?请输出全部购买方案。
12.某人想把一元钱换成伍分、贰分、壹分这样的零钱, 在这三种零钱中每种零钱都至少各有一个的情况下,共有多少种兑换方案。并打出这些方案。
13.
14. 输出100 以内的全部素数,要求每行显示5 个。
15.A、B两个自然数的和、差、积、商四个数加起来等于243,求A、B两数。
16.百钱买百鸡:今有钱100元,要买100只鸡,公鸡3元一只,母鸡1元一只,小鸡1元3只,若公鸡、母鸡和小鸡都至少要买1只,请编程求出恰好用完100元钱的所有的买鸡方案。
第二节 repeat 循环
Repeat循环是直到型循环。
试将上一节的例3.1(打印出1~20的平方数表)程序改为 repeat 循环:
Program Exam31_1;
Var a: byte;
Begin
a:=1; writeln ( ' a ' : 8 , ' a*a ' : 8 ) ;
repeat
writeln ( a :8,a*a : 8);
inc(a); {改变a的值 }
Until a>20;
Readln
Emd.
程序中的Repeat循环格式为:
repeat
循环体语句;
until 条件表达式; {直到条件为真}
Repeat循环首先执行由Repeat和Until括起来的循环体语句,然后检查Until后面的条件表达式:如果表达式结果为假,则继续执行循环体,接着继续检查Until后面的条件表达式,如此反复执行直到这个表达式结果为真时结束循环。Repeat循环体语句必须有能改变Until后面条件表达式值的语句,并最终使这个条件表达式的值为真,使循环自动结束。
程序中inc (a) 指令相当于a : =a+1,常用的同类指令格式如下:
(1) inc(x) 等同 x:=x+1;
(2) inc(x, n) 等同 x:=x+n;
(3) dec(x) 等同 x:=x—1;
(4) dec(x,n) 等同 x:=x—n;
[例3.10]求两个自然数M和N的最大公约数。
解:若自然数a既是M和约数,又是N的约数,则称a为M和N的公约数,其中最大的称为最大公约数。为了求得最大公约数,可以从最大可能的数(如M或N)向下寻找,找到的第一个公约数即是最大公约数。
Pascal程序:
Program ex310;
Begin
a := N+1;
Repeat
a := a-1;
Until (M mod a=0) and (N mod a=0);
writeln(a);
Readln;
End.
[例3.11]校体操队到操场集合,排成每行2人,最后多出1人;排成每行3人,也多出1人;分别按每行排4,5,6人,都多出1人;当排成每行7人时,正好不多。求校体操队至少是多少人?
解:①设校体操队为X人,根据题意X应是7的倍数,因此X的初值为7,以后用inc(x,7)改变X值;
②为了控制循环, 用逻辑变量yes为真(True) 使循环结束;
③如果诸条件中有一个不满足, yes 的值就会为假(false),就继续循环。
Pascal程序:
program Exam311;
var x: word; yes : boolean;
begin
x:=0;
repeat
yes :=true; inc(x,7);
if x mod 2 < > 1 then yes:=false;
if x mod 3 < > 1 then yes:=false;
if x mod 4 < > 1 then yes:=false;
if x mod 5 < > 1 then yes:=false;
if x mod 6 < > 1 then yes:=false;
until yes; {直到yes的值为真 }
writeln('All =', x) ; readln
end.
程序中对每个X值,都先给Yes 赋真值,只有在循环体各句对X进行判断时,都得到“通过”(此处不赋假值)才能保持真值。
[例3.12]从键盘输入一个整数X(X不超过10000),若X的各位数字之和为7的倍数,则打印“Yes”,否则中打印“No”。
解:本题考察的是数字分离的方法,由于X的位数不定,所以以往的解法不能奏效,这是介绍一种取余求商法。
(1)用X mod 10分离出X的个位数字;
(2)用X div 10将刚分离的个数数字删除,并将结果送回给X;
(3)重复(1)(2)直到X=0。
Pascal程序:
Program ex12;
var x,a,s : integer;
begin
s := 0;
repeat
a := x mod 10;
x := x div 10;
s := s+a;
until x=0;
if s mod 7=0 then writeln(‘Yes’)
else writeln(‘No’);
Readln;
end;
[例3.13]求1992个1992的乘积的末两位数是多少?
解:积的个位与十位数只与被乘数与乘数的个位与十位数字有关,所以本题相当于求1992个92相乘,而且本次的乘积主下一次相乘的被乘数,因此也只需取末两位参与运算就可以了。
Pascal程序:
Program ex313;
var a,t : integer;
Begin
a := 1;
t := 0;
repeat
t := t+1;
a := (a*92) mod 100;
until t=1992;
writeln(a);
Readln;
End.
[例3.14]尼科彻斯定理:将任何一个正整数的立方写成一组相邻奇数之和。
如: 33=7+9+11=27 43=13+15+17+19=64
解:从举例中发现:
(1) n3正好等于n个奇数之和;
(2) n个奇数中的最小奇数是从1开始的奇数序列中的第m个奇数,与 n 的关系为: m=n (n —1) / 2+1。
(3) 奇数序列中第m个奇数的值为x,且 x= 2m—1,比如: n=3时,m=3(3-1)/2+1=4,即3个奇数中最小的奇数是奇数序列中的第4个,它的值为x=(2m-1)=7, 所以:33=7+9+11。
(4) 从最小的奇数值x开始,逐个递增2,连续n个,用t从1开始计数,直到t=n为止。
Pascal程序:
Program Exam35;
Var n,m,x,t,s : integer;
Begin
write(’input n:’); readln(n); {输入N }
m:=(n*(n-1) div 2)+1; {找到第m个奇数 }
x:=2*m-1; t:=1; {算出第m个奇数的值x,是所求的第一个}
write(n’*’,n,’*’,n,’=’,x);{输出第一个}
s:=x; {用S计算和 }
if n>1 then
Repeat
inc(x,2); { 计算下一个奇数 }
write (’+ ’,x) ; {加上下一个奇数 }
inc (t ); inc (s,x); { 计个数并累加和 }
Until t=n; {直到n个 }
Writeln (’= ’,s ) ;
Readln
End.
[例3.15]猜价格:中央电视台的“幸运52”栏目深受观众喜爱,其中的“猜商品价格”的节目更是脍炙人口,现在请你编一个程序模拟这一游戏:由计算机随机产生200至5000之间的一个整数,作为某件商品的价格,然后由你去猜是多少,若你猜的数大了,则计算机输出提示“Gao”,若你猜的数小了,则计算机输出提示“Di”,然后你根据提示继续猜,直到你猜对了,计算机会提示“Ok”,并统计你猜的总次数。
解:本题的游戏规则大家都清楚,要完成程序,必须把处理步骤理清:
(1)用随机函数Random产生200至5000之间的一个整数X;
(2)你猜一个数A;
(3)若A>X,则输出“Gao”;
(4)若A<X,则输出“Di”;
(5)若A=X则输出“Ok”;
(6)重复(2)(3)(4)(5)直到A=X。
Pascal程序:
Program ex315;
Var t,X,a : integer;
Begin
Randomize;
X := Random(4800)+200;
t := 0;
Repeat
t := t+1;
write(‘[‘,t,’] Qing cai yi ge zheng shu : ‘);
readln(a);
if a>x then writeln(‘Gao’);
if a<x then writeln(‘Di’);
if a=x then writeln(‘Ok’);
Until A=X;
Readln;
End.
习题3.2
1.求两个自然数M和N的最小公倍数。(如果求三个或更多个数的最小公倍数呢?应如何解决)
2.小会议室里有几条相同的长凳,有若干人参加开会。如果每条凳子坐6人,结果有一条凳子只坐有3人;如果每条凳子坐5人,就有4人不得不站着。求会议室里有多少人开会,有多少条长凳?
3.某动物饲养中心用1700元专款购买小狗(每只31元)和小猫(每只21元)两种小动物。要求专款专用,正好用完, 应当如何购买?请输出所有方案。
4.某整数X加上100就成为一个完全平方数,如果让X加上168 就成为另一个完全平方数。求X?
5.某次同学聚会,老同学见面个个喜气洋洋,互相握手问好。参加此次聚会者每人都与老同学握了一次手,共握903次,试求参加聚会的人数?
6.用自然数300,262,205,167分别除以某整数A,所得到的余数均相同。求出整数A以及相除的余数?
7.1600年前我国的一部经典数学著作中有题:“今有物,不知其数,三三数之,剩二;五五数之,剩三;七七数之,剩二,问物几何。”求最小解。
8.编程求出所有不超过1000的数中,含有数字3的自然数,并统计总数。
9.阿姆斯特朗数:如果一个正整数等于其各个数字的立方和,则该数称为阿姆斯特朗数(也称自恋数),如407=43+03+73,试编程求出1000以内的所有阿姆斯特朗数。
第三节 While 循环
While循环是当型循环。
[例3.8] 前面第一章[例1.2]的鸡兔同笼,头30,脚90, 求鸡兔各几只?在此用下面方法编程求解。
解: 设鸡为J只,兔为T只。已知头为H, 脚为F。
①让鸡的只数逐次加1进行递推计算,初始时J=0;
②计算兔的只数T=H-J;
③当总脚数(4*T+2*J) < > F就做 (J=J+1,T=H-J);
④当4*T+2*J=F时,说明所推算的J和T是正确的,应结束循环,并输出T, J。
Pascal程序:
Program Exam38;
Const H=30;
F=90;
Var J,T : integer;
Begin
J:=0; T:=H-J; {初始时让J从0开始计算 }
While 4*T+2*J<>F do {当条件为真就做do后面的循环体 }
begin
inc(J); { 递推改变J值 }
T:=H-J {计算兔的只数 }
end;
Writeln('T=',T,' ':6, 'J=', J ) ;
Readln
End.
程序中采用While当型循环,While循环语句的格式为:
While 条件式 do 语句;
其中do后面的“语句”是被重复执行的,称为循环体;若循环体是多个语句, 必须用begin--end包起来成为复合语句。
While循环首先判断条件式,当条件式的值为真就执行do 后面的语句(循环体)。
While的循环体内也必须包含能改变控制变量取值语句, 影响条件式的值, 最终使条件式为false (假), 才能结束循环。
[例3.9] 输入任一的自然数A, B, 求A , B的最小公倍数。
解:这里采用适合计算机查找的方法: 设D是它们的最小公倍数。先找出A, B当中的较大者并存放在A中, 将较小者存放在B中, 让D=A, 当D能够整除B时, 则D是所求的最小公倍数;当D不能整除B,就逐次地让D增加A。例如:A=18, B=12, 步骤如下:
① 让D=A (D=18)
② 当(D mod B)<>0 为真时 ( D不能整除B ) 就做 D=D+A, 重复②;
③ 当(D mod B)<>0 为假时结束循环,并输出D。
Pascal程序:
program Exam39;
var a,b,d,t : word;
begin
write('input a,b: '); readln(a , b);
if a<b then
begin
t:=a; a:=b; b:=t
end;
d:=a;
while d mod b < >0 do {当条件为真时就做do后面的语句 }
inc(d,a);
writeln('[', a, ' , ' , b, ']=', d) ;
readln
End.
Pascal语言的三种基本循环方式, for循环对循环范围有明确规定, 且循环变量只能是递增加1或递减1自动计数控制; 而repeat--until循环和while--do循环比较灵活, 只要对条件表达式的值能控制满足一定要求就能组成循环, 但在循环体中必须有改变循环变量值的语句, 使条件判断(逻辑值)最终为True或flase, 让循环能够终止。
[例3.10]求自然数A, B的最大公约数。
解:采用如下方法步骤:
(1)求A除以B的余数;
(2)当余数<>0就做n=a; a=b; b=n mod b, 重复(1)和(2);
(3)当余数=0就结束循环,并输出b值。
比如a=18, b=12时,处理步骤为:
(1) = ,得余数为6;
(2) 此余数不为零 ,让a = 12, b = 6;
(3) 重复 = , 得余数为0;
(4) 结束循环,输出6(余数为零时的b值即是所求的最大公约数)。
此方法称为辗转相除法求最大公约数。
Pascal程序:
program Exam310;
var a,b, n : word;
begin
write('input a,b: '); readln (a,b);
write('(', a, ' , ' , b, ')=' ) ;
while a mod b < > 0 do
begin
n:=a; a:=b; b:=n mod b;
end;
writeln(b);
readln
End.
[例3.11]将一根长为369cm的钢管截成长为69cm和39cm两种规格的短料。在这两种规格的短料至少各截一根的前提下, 如何截才能余料最少。
解:设两种规格的短料分别为:
规格为69cm的x根,可在1至(369-39)/69范围循环取值;
规格为39cm的y根,用y = (369-69*X)/39)计算;
余料R=369-69*X-39*Y。
①设最小余料的初始值min=369;
②在X循环范围内,每一个X值都计算出对应的Y和R;
③如果R<min, 就将R存入min, x存入n, y存入m,记录余料最小时的x和y ;
④重复步骤②,当x值超出 ((369—39)/ 69) 时结束循环。
Pascal程序:
program exam311;
var x,y,r,min,n,m,a: integer;
begin
min:=369;
a:=(369-39) div 69; x:=1;
while x<=a do
begin
y:=(369-69*x) div 39;
r:=369-69*x-39*y;
if r<min then
begin
min:=r; n:=x; m:=y
end;
inc(x);
end;
writeln('min=', min, ' x=', n, ' y=', m) ;
readln
end.
在有些情况中, 三种循环方法可以互相换用。
[例3.12]甲、乙、丙三人都是业余射击爱好者, 在一次练习中他们枪枪中靶: 甲射了八发子弹,取得225环成绩,乙射了七发,也取得225环;丙只射了六发,同样取得225环。下面是成绩表,请编程完成下表中空项的填数。
|
射子弹数 |
中50环有几发 |
中35环有几发 |
中25环有几发 |
成绩(环) |
甲 |
8 |
|
|
|
225 |
乙 |
7 |
|
|
|
225 |
丙 |
6 |
|
|
|
225 |
解:①设N为发射子弹数, 只有8, 7, 6三个数字, 正好又可用来代表甲、乙、丙;
②设A为中50环的子弹数, 最小为0, 最大为(225 div 50=4);
B为中35环的子弹数, 最小为0, 最大为(225 div 35=6);
C为中25环的子弹数, C=N-A-B, 但必须C>0才可能正确;
③先让N=8, A取值(0~4), B取值 (0~6)用循环逐个选定, 在C>0的情况下若能满足条件A*50+B*35+C*25=225就能确定一组填数。然后选N的下一数值,重复同样的过程。
Pascal程序:
program exam312;
var a,b,c,n,s : integer;
begin
writeln('n':3, 'a':3, 'b':3, 'c':3, 's':5) ;
n:=8;
while n<=6 do
begin
a:=0;
while a < = 4 do
begin
b:=0;
while b < = 6 do
begin
c:=n-a-b;
if c>0 then
begin
s:=50*a+35*b+25*c;
if s=225 then writeln(n:3,a:3,b:3,c:3,s:5);
end;
inc(b);
end;
inc(a);
end;
dec(n);
end;
readln
end.
程序运行结果获得两组填数答案。如果改用for循环,程序将更加简明:
Program Exam312_1;
Var a,b,c,n,s : Integer;
Begin
Writeln('N':3, 'A':3, 'B':3, 'C':3, 'S':5) ;
for n:=8 downto 6 do {N取值8,7,6,并分别代表甲、乙、丙 }
for a:=0 to 4 do {中50环的可能范围 }
for b:=0 to 6 do {中30环的可能范围 }
begin
c:=n-a-b; { 计算中25环的子弹数 }
if c>0 then begin {如果不是负数 }
s:=50*a+35*6+25*c; {计算总成绩 }
if s=225 then writeln(n:3,a:3,b:3,c:3,s:5);
end
end;
readln
End.
习题3.3
1.求S= 1-1/2 +1/3-1/4+1/5-1/6+ ……(求前N项的和)
2. Faibonacci数列前几项为: 0,1,1,2,3,5,8,…,其规律是从第三项起, 每项均等于前两项之和。求前30项, 并以每行5个数的格式输出。
3.小球从100高处自由落下,着地后又弹回高度的一半再落下。求第20次着地时, 小球共通过多少路程?
4.某登山队员第一天登上山峰高度的一半又24米; 第二天登上余下高度的一半又24米;每天均如此。到第七天,距山顶还剩91米。求此山峰的高度?
5.给出某整数N,将N写成因数相乘的形式。如: N=12,输出: 12=1*2*2*3.
6.出售金鱼者决定将缸里的金鱼全部卖出。第一次卖出全部金鱼的一半加二分之一条;第二次卖出剩余的三分之一加三分之一条金鱼;第三次卖出余下金鱼的四分之一加四分之一条;第四次卖出余下的五分之一加五分之一条金鱼。还剩下11条金鱼。当然,出售金鱼时都是整数条,不能有任何破损。求缸里原有的金鱼数?
7.外出旅游的几位朋友决定次日早晨共分一筐苹果。天刚亮,第一个人醒来,他先拿了一个,再把筐里的八分之一拿走;第二个人醒来,先拿两个,再把筐里的八分之一拿走;第三个人醒来,先拿三个,再拿走筐里的八分之一;…每个人依次照此方法拿出各人的苹果,最后筐里的苹果全部拿完,他们每人所拿到的苹果数正巧一样多。求原先筐里的苹果数和人数。
8.图中由6个圆圈构成三角形,每条边上有三个圈, 将自然数1--6 不重复地填入各圆圈位置上,使每条边圆圈上的数字之和相等,请编程输出所有的填法。
9.请编程显示出下面数字金字塔图形:
程序中往往需要把主要任务分成若干个子任务,每个子任务只负责一个专门的基本工作。每个子任务就是一个独立的子程序。Turbo Pascal 可以把函数和过程作为子程序调用。
Pascal允许用户在程序中自己说明定义所需要的函数并在程序中调用这些函数。
[例4.1]编程找出由键盘任意输入五个整数中的最大整数。
解:设输入的五个整数为n1、n2、n3、n4、n5,为了便于处理,引入一个中间变量t1,按如下步骤处理:
①令t1=n1;
②将t1与n2比较,将两者中较大的数放入t1;
③将t1与n3比较,将两者中较大的数放入t1;
④将t1与n4比较,将两者中较大的数放入t1;
⑤将t1与n5比较,将两者中较大的数放入t1;
⑥经过以上5步处理后,t1即为5个数中最大者。
从上面规划的步骤看来,从步骤②到步骤⑤需处理的目标是相同的,因此我们可以设计一段子程序Max(x1,x2),以找出x1和x2中最大的值并返回。
Pascal程序:
Program Exam41_a;
Var n1,n2,n3,n4,n5,t1 : integer;
Function max(x1,x2 : integer) : integer;
Begin
If x1>x2 then Max := x1
Else Max := x2;
End;
Begin
Write(‘Input 5 numbers : ‘);
Readln(n1,n2,n3,n4,n5);
T1 := n1;
T1 := Max(t1,n2);
T1 := Max(t1,n3);
T1 := Max(t1,n4);
T1 := Max(t1,n5);
Writeln(‘Max number : ‘,t1);
End.
从上例看出,引入函数实际上是将一个复杂的问题划分成若干个易于处理的子问题,将编程化简的一种有效办法,而化简的方法是多种多样的,如前面已经做过求三个数中的最大数,所以可定义一个专门求三个数中最大数的函数(Max)。第一次用这个函数求出n1,n2,n3三个数中的最大数t1;第二次调用这个函数求出t1与n4,n5三个数中的最大数,也就是前三个数的最大数(已在t1中)和后面二个数再求一次,就得到五个数的最大数。因此,需要两次使用“求三个数中的最大数”,步骤如下:
①调用函数Max ( n1, n2, n3),求出n1,n2,n3中的最大者 t1;
②调用函数Max ( t1, n4, n5 ),求出t1, n4, n5中的最大者t2;
③输出最大数 t2。
Program Exam41_b;
Var n1,n2,n3,n4,n5,t1: integer;
function Max(x1,x2,x3: integer): integer; {自定义函数Max}
Var XX: integer; {函数内部变量说明}
begin {函数体}
if X1>X2 then XX:=X1
else XX:=X2;
if X3>XX then XX:=X3;
Max:=XX
end;
Begin {主程序}
Write('Input 5 numb:');
Readln(n1,n2,n3,n4,n5); {输入五个数}
t1:=Max(n1,n2,n3); {用函数求n1, n2, n3的最大数}
t1:=Max(n4,n5,t1); {用函数求n4, n5, t1 的最大数}
Writeln('Max Number :', t1);
Readln
End.
主程序中两次调用自定义函数。自定义函数的一般格式为:
function 函数名(形式参数表): 类型; {函数首部}
局部变量说明部分;
begin
语句系列; {函数体 }
end;
函数中的形式参数接受调用函数时所传入的值,用来参与函数中的运算。
[例4.2]求任意输入的五个自然数的最大公约数。
解:⑴自定义一个专门求两自然数的最大公约数的函数GCD;
⑵调用自定义函数,第一次求前两个数的最大公约数;从第二次开始,用每次求得的最大公约数与下一个数再求两个数最大公约数,直到最后。本题共四次“求两个数的最大公约数”, 设输入的五个自然数分别是a1,a2,a3,a4,a5,采用如下步骤:
①求a1, a2两个数的最大公约数 → 存入a1;
②求a1, a3两个数的最大公约数 → 存入a1;
③求a1, a4两个数的最大公约数 → 存入a1;
④求a1, a5两个数的最大公约数 → 存入a1;
⑤ 输出 a1,此时的a1已是五个数的最大公约数。
Pascal程序:
Program Exam42;
Var a1,a2,a3,a4,a5: integder;
function GCD(x,y: integer): integer; {自定义函数 }
Var n:integer;
begin
While x mod y <>0 do
begin
n:=x; x:=y; y:=n mod y
end;
GCD:=y
end;
Begin {主程序 }
Write('input 5 Numper:');
readln(a1,a2,a3,a4,a5); {输入五个数}
Write('(',a1,',',a2,',',a3,',',a4,',',a5,')=');
a1:=GCD(a1,a2); {调用函数GCD }
a1:=GCD(a1,a3);
a1:=GCD(a1,a4);
a1:=GCD(a1,a5);
Writeln(a1);
readln
End.
函数的结果是一个具体的值, 在函数体中必须将所得到的运算结果赋给函数名;主程序通过调用函数得到函数的运算结果。调用函数的一般格式为:
函数名 (实在参数表)
调用函数时, 函数名后面圆括号内的参数必须有确定的值, 称为实在参数。调用时即把这些实际值传送给函数形参表中的相应形参变量。函数不是单独的语句, 只能作为运算赋值或出现在表达式中。
习题4.1
1. 数学上把从 1 开始的连续自然数相乘叫做阶乘。例如 把1*2*3*4*5 称作5的阶乘, 记为5!。 编写一个求n!的函数, 调用此函数求: D=
2.求从键盘输入的五个自然数的最小公倍数。
3.哥德巴赫猜想的命题之一是:大于6 的偶数等于两个素数之和。编程将6~100所有偶数表示成两个素数之和。
4.如果一个自然数是素数,且它的数字位置经过对换后仍为素数,则称为绝对素数,例如13。试求出所有二位绝对素数。
自定义函数通常被设计成求一个函数值,一个函数只能得到一个运算结果。若要设计成能得到若干个运算结果,或完成一系列处理,就需要自定义“过程”来实现。
[例4.3] 把前面[例2.2 ](输入三个不同的整数,按由小到大排序)改为下面用自定义过程编写的Pascal程序:
Program exam43;
Var a,b,c: integer;
Procedure Swap (var x,y: integer); {自定义交换两个变量值的过程 }
Var t : integer;
Begin {过程体}
t:=x; x:=y; y:=t {交换两个变量的值
end;
Begin {主程序}
Write('input a,b,c=');
Readln(a,b,c);
if a>b then swap (a,b); {调用自定义过程}
if a>c then swap (a,c);
if b>c fhen swap (b,c);
Writeln (a:6, b:6, c:6);
Readln
End.
程序中Procedure Swap是定义过程名,从作用来看,过程与函数是相似的,都能将复杂的问题划分成一些目标明确的小问题来求解,只不过函数有值返回而过程则没有。自定义过程的一般格式如下:
Procedure 过程名 (形式参数表); {过程首部}
局部变量说明部分;
begin
语句部分; {过程体部分}
end;
[例4.4]如果一个自然数除了1和本身,还有别的数能够整除它, 这样的自然数就是合数。例如15,除了1和15,还有3和5能够整除,所以15是合数。14,15,16是三个连续的合数,试求连续十个最小的合数。
解:从14,15,16三个连续合数中可看出,它们正好是两个相邻素数13和17 之间的连续自然数,所以求连续合数问题可以转化为求有一定跨度的相邻两个素数的问题。因此,求连续十个最小的合数可用如下方法:
①从最小的素数开始,先确定第一个素数A;
②再确定与A相邻的后面那个素数B;(作为第二个素数);
③检查A,B的跨度是度否在10 以上,如果跨度小于10,就把B 作为新的第一个素数A,重复作步骤②;
④如果A、B跨度大于或等于10,就打印A、B之间的连续10个自然数,即输出 A+1, A+2, A+3 …, A+10。
Pascal程序:
Program exam44;
var a,b,s,n: integer;
yes: boolean;
procedure sub(x: integer;var yy: boolean); {过程:求x是否为素数 }
var k,m: integer; { 用yy逻辑值转出 }
begin
k:=trunc(sqrt(x));
for m:=3 to k do
if odd(m) then
if x mod m=0 then yy:=false;
end;
begin {主程序 }
b:=3;
repeat
a:=b; {a 为第一个素数 }
repeat
yes:=true;
inc(b,2); {b是a后面待求的素数}
sub(b,yes); {调用SUB过程来确认b是否为素数 }
if yes then s:=b-a; {如果b是素数,则求出跨度s }
until yes;
until s > = 10;
for n:=a+1 to a+10 do
write(n:6);
writeln;
readln
end.
程序中的过程SUB,用来确定b是否为素数。过程名后面圆括号内的变量是形式参数,简称为形参。过程SUB(x: integer; Var yy: boolean) 中的x是值形参,而前面冠有Var的yy是变量形参。值形参只能从外界向过程传入信息,但不能传出信息;变量形参既能传入又能传出信息。本程序过程SUB中的x是由调用过程的实在参数b传入值,进行处理后,不需传出;而yy是把过程处理结果用逻辑值传出,供调用程序使用。
试把[例4.3]程序中的过程 SWAP(Val x,y: integer),将x,y前面的Var去掉,就变成了纯粹的值形参,就不能将过程所处理的结果传出去,也就无法得到处理后的结果,通过运行程序比较,可以非常明显地看到值形参和变量形参的区别。
调用过程的格式为: 过程名(实在参数表) ;
调用过程名后面圆括号内的实在参数与定义过程的形参表必须相对应,调用过程相当于一个独立语句,可单独使用。
[例4.5]将合数483的各位数字相加(4+8+3)=15,如果将483分解成质因数相乘: 483=3*7*23,把这些质因数各位数字相加(3+7+2+3),其和也为15。即某合数的各位数字之和等于它所有质因数的各数字之和。求500以内具有上述特点的所有合数。
解:①设n为所要求的合数,让n在1~500间循环做以下步骤;
②用t1,t2分别累计合数n及n的质因数的各位数字之和,初值均为0;
③调用过程SUB3进行非素数判定,以布尔变量yes的真假值判定是否,yes的初值为true,如果为 (not true)非素数,就做步骤④,⑤,⑥;否则取新的n值,重复步骤③;
④调用SUB1,求n的各数字之和,传送给t1;
⑤调用SUB2,求n的各质因数,对于每个质因素都通过SUB1求它各位数字之和,将所有各质因数字传送给t2。
⑥如果t1=t2(各位数字之和等于它所有质因数的各数字之和),则输出此n。
PASCAL程序:
program exam45;
var n,t1,t2,tatol: integer;
yes: boolean;
procedure sub1(x:integer; var t:integer); {过程:分离x的各位数字 }
begin {并求各位数字之和 }
repeat
t:=t+x mod 10;
x:=x div 10;
until x=0
end;
procedure sub2(x: integer; var t: integer); {过程:分解质因数 }
var xx,tt:integer;
begin
xx:=2;
while x>1 do
if x mod xx=0 then
begin
tt:=0;
sub1(xx,tt);
t:=t+tt;
x:=x div xx
end
else inc(xx)
end;
procedure sub3(x: integer;var yy: boolean); {过程:判断x是否为素数 }
var k,m: integer;
begin
k:=trunc(sqrt(x));
for m:=2 to k do
if x mod m=0 then yy:=false;
end;
begin {主程序}
for n:=1 to 500 do
begin
t1:=0;t2:=0;
yes:=true;
sub3(n,yes); {调用过程求素数 }
if not yes then {如果非素数就… }
begin
sub1(n,t1); {调用过程求n的各位数字之和 }
sub2(n,t2); {调用过程求n的各质因数的数字之和 }
if t1=t2 then write(n:6); {打印合格的合数 }
end
end;
readln
end.
程序定义了三个过程SUB1,SUB2,SUB3,其中SUB2过程中又调用了SUB1。在过程中定义的变量或参数,只在本过程内部使用有效。这些变量称为局部变量。如SUB2中的xx只在SUB2中使用,属于局部变量。
习题:4.2
1.输入自然数n,求前n个合数(非素数),其素因子仅有2,3,或5。
2.自然数a的因子是指能整除a的所有自然数,但不含a本身。例如12的因子为:1,2,3,4,6。若自然数a的因子之和为b,而且b的因子之和又等于a,则称a,b为一对“亲和数” 。求最小的一对亲和数。
3.求前n个自然数的平方和,要求不用乘法。例如:3的平方不用3*3,可用3+3+3。
4.试用容积分别为17升、13升的两个空油桶为工具,从大油罐中倒出15升油来,编程显示出具体的倒油过程。
5.如果一个数从左边读和从右边读都是同一个数,就称为回文数。例如6886就是一个回文数,求出所有的既是回文数又是素数的三位数。
6. 任何大于2的自然数都可以写成不超过四个平方数之和。如:
8=22+22; 14=12+22+32 由键盘输入自然数N(2 < N < 2000),输出其不超过四个平方数之和的表示式。