pascal-算法例题 - 图文

2019-03-11 11:04

中山纪念中学信息学奥林匹克算法设计题选

算法设计题选

(一)、算法设计:

一、筛选法

1:求1—100间的所有素数。

分析:用筛选法,先把2—100的数存到一个数组中,然后先把2的所有倍数删除掉(即让此数变为0),再删3的倍数,继续往上就是5的倍数,7的倍数??,最后,剩下的数(即数组中不为0的数)就是素数。 Var n:array[2..100] of integer; I,j,k:integer; Begin For I:=2 to 100 do n[I]:=I; I:=2; Repeat J:=1; Repeat J:=j+1; K:=I*j; if n[k]>0 then N[k]:=0; Until (j+1)*i>100; Repeat i:=i+1; until (n[i]>0) or (i>50); Until i>50; for i:=2 to 100 do if n[i]>0 then write(n[i]:4); end. 另外,该题也可利用集合来做,同样用筛选法: var ss:set of 2..100; 集合SS用来存放数 i,j,k:integer; begin ss:=[2..100]; for i:=2 to 50 do begin 把SS中2至50的倍数全部删除 j:=1; repeat j:=j+1; k:=i*j; if k in ss then ss:=ss-[k]; until k+i>100; end; for i:=2 to 100 do if i in ss then write(i:3); end. 2:不相同的余数问题,即“秦王暗点兵”或“韩信点兵”: 有一楼房的楼梯级数很奇特,一步跨二级多一级,一步跨三级多二级,如果分用四、五、六、七去除级数分别余三、三、五、五。问这楼房共有多少级阶梯?(已知不超过400级)。

分析:已知级数不超过400级,我们可仿照求素数的方法,把1—400存进一个数组中,然后这些数用2、3、4、5、6、7分别去除,如果余数分别不为1、2、3、3、5、5就删除它,最后,最小的一个没有被删除的数就是解。 Var n:array[1..400] of integer; I,j,k:integer; Const a:array[1..6] of integer=(2,3,4,5,6,7); 除数 b:array[1..6] of integer=(1,2,3,3,5,5); 余数 第 1 页 共 31页

中山纪念中学信息学奥林匹克算法设计题选 Begin For I:=1 to 400 do n[I]:=I; for i:=1 to 6 do begin for k:=1 to 400 do begin if n[k]>0 then begin if k mod a[i]<>b[i] then begin n[k]:=0; end; end; end; end; i:=0; repeat 找最小的一个没有被删除的数 i:=i+1; until n[i]>0; write(n[i]:4); end. 分析:用上述方法由于要删除的数非常多,因此速度较慢,我们可以反过来想,把满足余数条件的数加上记号,最后,最小的一个加上了六个记号的数就是答案。 Var n:array[1..400] of integer; I,j,k:integer; const a:array[1..6] of integer=(2,3,4,5,6,7); b:array[1..6] of integer=(1,2,3,3,5,5); Begin For I:=1 to 400 do n[I]:=0; for k:=1 to 400 do begin for i:=1 to 6 do begin if k mod a[i]=b[i] then n[k]:=n[k]+1; end; end; i:=0; repeat i:=i+1; until n[i]=6; write(i:4); end. 这样,速度要快很多。大家思考一下下题:《孙子算法》有题:今有物,不知其数。三、三数之,剩二;五、五数之,剩三;七、七数之,剩二。问物几何?(最小正数解)。

3:狼追兔子,兔子躲进了10个环形分布的洞的某一个中。狼在第1个洞中没有找到兔子,就间隔1个洞,到第3个洞中去找,也没找到兔子,就间隔2个洞,到第6个洞中去找。以后狼每次多隔1个洞去找兔子,??。这样狼一直找不到兔子。请问兔子可能躲在哪个洞中?

分析:该题看似简单,只要每次把狼找过的洞删除就行了,但是,这种删除操作的结束状态(条件)是什么呢?而且,狼的搜索过程中,如果要间隔11个洞时,我们是否可以认为就是间隔1个洞?

实际上,第一个问题应该是当狼回到第1个洞,并且又上间隔1个洞去找兔子时,就应该结束删除操作,因为此后的搜索是重复以前的搜索了,此时,那些没有被删除过的洞就是答案。这里,大家一定不能想当然地认为:结束条件就是只剩下一个洞的时候!题目中并没有说明只有一个答案,事实上是有四个洞的!

第二个问题也是可行的。因为只有10个洞,间隔11个洞和间隔1个洞的作用是相同的。 var d:array[1..10] of integer; i,j,k,l:integer; begin for i:=1 to 10 do d[i]:=1; 第 2 页 共 31页

中山纪念中学信息学奥林匹克算法设计题选 i:=1; j:=1; repeat d[i]:=0; j:=j+1; if j>10 then j:=j-10; i:=i+j; if i>10 then i:=i-10; until (i=1) and (j=1); for i:=1 to 10 do if d[i]>0 then write(i); end. 习题

1、作800—1000的素数表。

答案:809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997

2、一位数学家和一些游客共81人不幸落入强盗手中,强盗把俘虏排成一队,宣布每天处理所有第2的N次方个俘虏(N>=0),而只放走剩下的最后一个。由于数学家身怀重任,不得不选择了一个恰当的位置而最终被放走。请问他归初排在第几个位置。 答案:80

3、有一堆礼物,工作人员无论是分成二个一份,还是三个、四个、五个、六个一份,总是多一个。请问这堆礼物至少多少个? 答案:61

4、一付扑克中拿出所有的黑桃A??K按顺序排好。第一次翻出第一张牌——A,放在一边,再拿出第二张放到牌的最下面。以后每次都翻出一张牌,再把一张牌放到最后,问第八次翻出的牌是哪一张? 答案:4

二、排序方法

本小节讨论几种排序方法。何为排序呢?就是把一些数字按递增或递减的顺序排列。例如:4,3,5,1,2这五个数,按从小到大的顺序排列是:1,2,3,4,5;按从大到小的顺序排列是:5,4,3,2,1。

1、双数组排序法: 用一个数组存放未经排序的数,然后按顺序找出未经排序数中的最大数,按顺序存放到另一个数组中,要考虑的问题是:怎样把未经排序数组中已经找出的数删除。 程序如下: uses crt;

var n,m:array[1..10] of integer; i,j,max,k:integer; begin

clrscr;

for i:=1 to 10 do read(n[i]);{读入10个数} for i:=1 to 10 do begin max:=0;

for j:=1 to 10 do begin {从数组N找到最大的数} if n[j]>max then begin

max:=n[j];

k:=j; {记住该位置}

end; end;

m[i]:=max;{存入数组M中}

n[k]:=-30000;{删除该数,把值变为-30000} end;

for i:=1 to 10 do write(m[i]:3);{打印已排好序的数}

第 3 页 共 31页

中山纪念中学信息学奥林匹克算法设计题选

end.

2、插入法排序: 插入法排序是把存放在数组中的未经排序的数逐个插入到另外一个数组中。如何找到每个数的正确位置呢?我们应该用动态查找的方法,从已排序的数组中从最左边开始查找,直到找到一个数大于等于待插入的数时,该数之前就是我们要找的位置。此方法可用数组来完成,也可用链表来完成。程序如下: 把数先存放在一个数组中,再逐个插入到另一个数组中: uses crt;

var n,m:array[1..10] of integer; i,j,k,l:integer; begin

clrscr;

for i:=1 to 10 do read(n[i]); {读入10个数存放到数组N中} m[1]:=n[1]; {在数组M中存放第一个数} for i:=2 to 10 do begin {把数组N中第2到第10个数逐个插入到数组M中} j:=0; repeat

j:=j+1;

until (j=i) or (m[j]>=n[i]); {找到待插入的数在M中的位置} if j=i then m[j]:=n[i] else begin

for l:=i-1 downto j do m[l+1]:=m[l]; {把该位置后的数后移} m[j]:=n[i]; {把待插入的数放在正确位置} end; end;

for i:=1 to 10 do write(m[i]:3); {打印} end.

3、交换排序

交换排序法:这是最常用的一种排序方法,其实质是:先把数据存放在数组中,然后从第一个开始,分别与其后所有数据进行比较,如果第一个比其后某个数据小,则交换它们的值,一直到第一个与其后所有数据比较完,这时第一个数据就是最大的一个;然后再把第二个数据再与其后数据进行比较,比较完后,第二个数据则为第二大的,这样直到倒数第二个数据比较完后,整个数组就已经按从大到小的顺序排列了。其作用示意如下:

假设我们已经把6个数据分别存放在N[1]至N[6]中,其值分别为:3,1,5,9,2,6。 交换前的值为: 第一步,把第一个值与其后第一个进行比较,这时3>1,所以值不变: 第二步:把第一个值与其后第二个进行比较,这时3<5,所以值交换: 第三步:把第一个值与其后第三个进行比较,这时5<9,所以值交换: ?? 当第一个值与其后所有值比较完后,第一个值已经是最大的,数组值为: 这时,重复上述第一步的操作,只是把第一个值换成第二个值,第一个值即第二个值与其后第一个值进行比较,这时1<3,所以交换其值: 第二个值与其后所有值比较完后,数组值为: 再重复进行第三个值与其后值的比较,直到第五个值与第六个值比较完后,这时数组的值已经变为: 至此,数组已经按从大到小的顺序排好了。 程序如下 :[例6、1] Var n:array[1..10] of integer; 说明一个数组型变量 第 4 页 共 31页

3,1,5,9,2,6 3,1,5,9,2,6 5,1,3,9,2,6 9,1,3,5,2,6 ?? 9,1,3,5,2,6 9,3,1,5,2,6 9,6,1,3,2,5 9,6,5,3,2,1 中山纪念中学信息学奥林匹克算法设计题选 I,j,t:integer; Begin For I:=1 to 10 do Readln(n[I]); 从键盘读入10个数据存放在数组N中 For I:=1 to 9 do begin 参加比较的第一个数据为第1至第9个。 For j:=I+1 to 10 do begin 第二个数据为第一个数据之后所有的数据 If n[I]

四、选择排序: 设数组中有N个数,取I=1,2,3,??N-1,每次找出后N-I+1个数字中最小的与第I个数字交换位置。程序如下: uses crt;

var n:array[1..10] of integer; i,j,k,t,min:integer; begin

clrscr;

for i:=1 to 10 do read(n[i]); for i:=1 to 9 do begin min:=30000;

for j:=i to 10 do begin {在第I到第10个数中找到最小的一个} if n[j]

k:=j; {记录该位置} end; end; t:=n[i]; n[i]:=n[k]; n[k]:=t; end;

for i:=1 to 10 do write(n[i]:4); end.

5、快速排序:

(1)把N个数存放在数组S中,当前集合为S中所有数。 (2)把当前集合第一个数定为标准数K,把S分为两个子集,左边子集S1为小于等于K的数,右边子集S2为大于等于K的数。这一操作是这样完成的:(A)、设定集合第一个数作为标准数K,设定指针I、J,I指向集合第一个数,J指向集合最后一个数;(B)、把J向左移(J:=J-1),直到找到一个S[J]<=K,则交换S[I]与S[J]的位置,并把I后移(I:=I+1);(C)、把I向右移(I:=I-1),直到找到一个S[I]>=K,则交换S[I]与S[J]的位置,并把J前移(J:=J-1);(D)、重复B、C直到I=J。 (3)依次把S1、S2作为当前集合,以第一个数作为标准数K,重复第2步,直到S1、S2及其产生的子集元素个数为1。

第 5 页 共 31页


pascal-算法例题 - 图文.doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:临床医学外科学考试题 各论

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: