算法设计.docx

上传人:b****6 文档编号:6525754 上传时间:2023-01-07 格式:DOCX 页数:57 大小:233.50KB
下载 相关 举报
算法设计.docx_第1页
第1页 / 共57页
算法设计.docx_第2页
第2页 / 共57页
算法设计.docx_第3页
第3页 / 共57页
算法设计.docx_第4页
第4页 / 共57页
算法设计.docx_第5页
第5页 / 共57页
点击查看更多>>
下载资源
资源描述

算法设计.docx

《算法设计.docx》由会员分享,可在线阅读,更多相关《算法设计.docx(57页珍藏版)》请在冰豆网上搜索。

算法设计.docx

算法设计

算法设计题选

(一)、算法设计:

一、筛选法

1:

求1—100间的所有素数。

分析:

用筛选法,先把2—100的数存到一个数组中,然后先把2的所有倍数删除掉(即让此数变为0),再删3的倍数,继续往上就是5的倍数,7的倍数……,最后,剩下的数(即数组中不为0的数)就是素数。

Varn:

array[2..100]ofinteger;

I,j,k:

integer;

Begin

ForI:

=2to100don[I]:

=I;

I:

=2;

Repeat

J:

=1;

Repeat

J:

=j+1;

K:

=I*j;

ifn[k]>0thenN[k]:

=0;

Until(j+1)*i>100;

Repeat

i:

=i+1;

until(n[i]>0)or(i>50);

Untili>50;

fori:

=2to100doifn[i]>0thenwrite(n[i]:

4);

end.

另外,该题也可利用集合来做,同样用筛选法:

varss:

setof2..100;

i,j,k:

integer;

begin

ss:

=[2..100];

fori:

=2to50dobegin

j:

=1;

repeat

j:

=j+1;

k:

=i*j;

ifkinssthenss:

=ss-[k];

untilk+i>100;

end;

fori:

=2to100doifiinssthenwrite(i:

3);

end.

集合SS用来存放数

把SS中2至50的倍数全部删除

2:

不相同的余数问题,即“秦王暗点兵”或“韩信点兵”:

有一楼房的楼梯级数很奇特,一步跨二级多一级,一步跨三级多二级,如果分用四、五、六、七去除级数分别余三、三、五、五。

问这楼房共有多少级阶梯?

(已知不超过400级)。

分析:

已知级数不超过400级,我们可仿照求素数的方法,把1—400存进一个数组中,然后这些数用2、3、4、5、6、7分别去除,如果余数分别不为1、2、3、3、5、5就删除它(把它设为0),最后,最小的一个没有被删除的数就是解。

Varn:

array[1..400]ofinteger;

I,j,k:

integer;

Consta:

array[1..6]ofinteger=(2,3,4,5,6,7);

b:

array[1..6]ofinteger=(1,2,3,3,5,5);

Begin

ForI:

=1to400don[I]:

=I;

fori:

=1to6dobegin

fork:

=1to400dobegin

ifn[k]>0thenbegin

ifkmoda[i]<>b[i]thenbegin

n[k]:

=0;

end;

end;

end;

end;

i:

=0;

repeat

i:

=i+1;

untiln[i]>0;

write(n[i]:

4);

end.

除数

余数

找最小的一个没有被删除的数

分析:

用上述方法由于要删除的数非常多,因此速度较慢,我们可以反过来想,把满足余数条件的数加上记号,最后,最小的一个加上了六个记号的数就是答案。

Varn:

array[1..400]ofinteger;

I,j,k:

integer;

consta:

array[1..6]ofinteger=(2,3,4,5,6,7);

b:

array[1..6]ofinteger=(1,2,3,3,5,5);

Begin

ForI:

=1to400don[I]:

=0;

fork:

=1to400dobegin

fori:

=1to6dobegin

ifkmoda[i]=b[i]thenn[k]:

=n[k]+1;

end;

end;

i:

=0;

repeat

i:

=i+1;

untiln[i]=6;

write(i:

4);

end.

这样,速度要快很多。

大家思考一下下题:

《孙子算法》有题:

今有物,不知其数。

三、三数之,剩二;五、五数之,剩三;七、七数之,剩二。

问物几何?

(最小正数解)。

3:

狼追兔子,兔子躲进了10个环形分布的洞的某一个中。

狼在第1个洞中没有找到兔子,就间隔1个洞,到第3个洞中去找,也没找到兔子,就间隔2个洞,到第6个洞中去找。

以后狼每次多隔1个洞去找兔子,……。

这样狼一直找不到兔子。

请问兔子可能躲在哪个洞中?

分析:

该题看似简单,只要每次把狼找过的洞删除就行了,但是,(问题1)这种删除操作的结束状态(条件)是什么呢?

(问题2)而且,狼的搜索过程中,如果要间隔11个洞时,我们是否可以认为就是间隔1个洞?

实际上,第一个问题应该是当狼回到第1个洞,并且又上间隔1个洞去找兔子时,就应该结束删除操作,因为此后的搜索是重复以前的搜索了,此时,那些没有被删除过的洞就是答案。

这里,大家一定不能想当然地认为:

结束条件就是只剩下一个洞的时候!

题目中并没有说明只有一个答案,事实上是有四个洞的!

第二个问题也是可行的。

因为只有10个洞,间隔11个洞和间隔1个洞的作用是相同的。

vard:

array[1..10]ofinteger;

i,j,k,l:

integer;

begin

fori:

=1to10dod[i]:

=1;

i:

=1;

j:

=1;

repeat

d[i]:

=0;

j:

=j+1;

ifj>10thenj:

=j-10;

i:

=i+j;

ifi>10theni:

=i-10;

until(i=1)and(j=1);

fori:

=1to10doifd[i]>0thenwrite(i);

end.

习题

1、作800—1000的素数表。

答案:

809811821823827829839853857859863877881883887907911919929937941947953967971977983991997

2、有一堆礼物,工作人员无论是分成二个一份,还是三个、四个、五个、六个一份,总是多一个。

请问这堆礼物至少多少个?

答案:

61

3、一付扑克中拿出所有的黑桃A……K按顺序排好。

第一次翻出第一张牌——A,放在一边,再拿出第二张放到牌的最下面。

以后每次都翻出一张牌,再把一张牌放到最后,问第八次翻出的牌是哪一张?

答案:

4

4、六

(2)班有四个数学天才,数学才能令人惊叹,每次上课时都对数学老师的讲课进度不满,甚至经常怪老师讲的内容太简单,太慢,没有顾及他们四个天才的感受。

四个天才在数学课上那上活跃得不得了,基本上都是不等数学老师把课讲完就把答案给叫了出来,数学老师也没办法,大凡天才在小时候都是如此吧,数学老师安慰自己。

这天的数学课是老师公布同学们的评价后的第一节课,四位数学天才在过程性评价中得到的都是B,这下不得了了,四人一起合计,觉得数学老师欺人太甚了,非得在这节数学课上整整老师不可,大家想出了A计划、B计划甚至C计划,决定这次要给数学老师一个好看,让全班,不,是全校都知道他们四个数学天才的厉害。

可是令他们没想到的是,数学老师竟然先下手为强了,一上课还不等他们四人发难,就把他们四人叫到前面,这节课竟然是要让他们四个人做老师的道具!

老师让他们每人手上拿一张写着一个自然数的纸,不许说话,由坐在位置上的其他同学进行抢答,回答的答案就是一个自然数,但是要满足以下两个条件:

1、这个数能够被他们手上四个数字整除;

2、这个数是满足条件一的数字中最大的数。

四位天才分别来自四个组,但是他们不能说话,只能是他们自己组里的同学抢答答案,答对的加1分,答错的倒扣1分,而如果哪个天才说了话,那么他的组就将被扣2分!

最后得分最高的那个小组的每一位同学将获得老师的奖品——福娃,这太吸引人了,而且自己无论如何都不能说话,要不自己小组将肯定拿不到第一名了,那不得被同学们骂死才怪呢。

为了小组的荣誉,四位天才当然不能说话了,他们只能眼巴巴地看着自己的同学回答这些他们认为是简单得不得了的题,不过四位天才中的一位是位编程高手,他也没闲着,自己在大脑里把完成这个任务的程序给编了出来。

你能编写出这个程序吗?

输入格式:

ABCD(四个自然数,每个数都小于32767)

输出格式:

N(满足上述条件的自然数)

输入样例:

36912

输出样例:

3

测试数据:

序号

分值

输入

输出

1

20

1234

1

2

20

30000299972999429991

3

3

20

164824160

8

4

20

200400100300

100

5

20

2046885136

17

二、排序方法

本小节讨论几种排序方法。

何为排序呢?

就是把一些数字按递增或递减的顺序排列。

例如:

4,3,5,1,2这五个数,按从小到大的顺序排列是:

1,2,3,4,5;按从大到小的顺序排列是:

5,4,3,2,1。

1、双数组排序法:

用一个数组存放未经排序的数,然后按顺序找出未经排序数中的最大数,按顺序存放到另一个数组中,要考虑的问题是:

怎样把未经排序数组中已经找出的数删除。

程序如下:

varn,m:

array[1..10]ofinteger;

i,j,max,k:

integer;

begin

fori:

=1to10doread(n[i]);{读入10个数}

fori:

=1to10dobegin

max:

=0;

forj:

=1to10dobegin{从数组N找到最大的数}

ifn[j]>maxthenbegin

max:

=n[j];

k:

=j;{记住该位置}

end;

end;

m[i]:

=max;{存入数组M中}

n[k]:

=-30000;{删除该数,把值变为-30000}

end;

fori:

=1to10dowrite(m[i]:

3);{打印已排好序的数}

end.

2、插入法排序:

插入法排序是把存放在数组中的未经排序的数逐个插入到另外一个数组中。

如何找到每个数的正确位置呢?

我们应该用动态查找的方法,从已排序的数组中从最左边开始查找,直到找到一个数大于等于待插入的数时,该数之前就是我们要找的位置。

此方法可用数组来完成,也可用链表来完成。

程序如下:

把数先存放在一个数组中,再逐个插入到另一个数组中:

varn,m:

array[1..10]ofinteger;

i,j,k,l:

integer;

begin

fori:

=1to10doread(n[i]);{读入10个数存放到数组N中}

m[1]:

=n[1];{在数组M中存放第一个数}

fori:

=2to10dobegin{把数组N中第2到第10个数逐个插入到数组M中}

j:

=0;

repeat

j:

=j+1;

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

ifj=ithenm[j]:

=n[i]elsebegin

forl:

=i-1downtojdom[l+1]:

=m[l];{把该位置后的数后移}

m[j]:

=n[i];{把待插入的数放在正确位置}

end;

end;

fori:

=1to10dowrite(m[i]:

3);{打印}

end.

3、冒泡法排序

冒泡法:

这是最常用的一种排序方法,其实质是:

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

其作用示意如下:

假设我们已经把6个数据分别存放在N[1]至N[6]中,其值分别为:

3,1,5,9,2,6。

交换前的值为:

3,1,5,9,2,6

第一步,把第一个值与其后第一个进行比较,这时3>1,所以值不变:

3,1,5,9,2,6

第二步:

把第一个值与其后第二个进行比较,这时3<5,所以值交换:

5,1,3,9,2,6

第三步:

把第一个值与其后第三个进行比较,这时5<9,所以值交换:

9,1,3,5,2,6

……

……

当第一个值与其后所有值比较完后,第一个值已经是最大的,数组值为:

9,1,3,5,2,6

这时,重复上述第一步的操作,只是把第一个值换成第二个值,第一个值即第二个值与其后第一个值进行比较,这时1<3,所以交换其值:

9,3,1,5,2,6

第二个值与其后所有值比较完后,数组值为:

9,6,1,3,2,5

再重复进行第三个值与其后值的比较,直到第五个值与第六个值比较完后,这时数组的值已经变为:

9,6,5,3,2,1

至此,数组已经按从大到小的顺序排好了。

程序如下:

[例6、1]

Varn:

array[1..10]ofinteger;

I,j,t:

integer;

Begin

ForI:

=1to10doReadln(n[I]);

ForI:

=1to9dobegin

Forj:

=I+1to10dobegin

Ifn[I]

T:

=n[I];

N[I]:

=n[j];

N[j]:

=t;

End;

End;

End;

ForI:

=1to10dobegin

Write(n[I]:

5);

End;

End.

说明一个数组型变量

从键盘读入10个数据存放在数组N中

参加比较的第一个数据为第1至第9个。

第二个数据为第一个数据之后所有的数据

如果n[I]

打印排序后的结果

四、选择排序:

设数组中有N个数,取I=1,2,3,……N-1,每次找出后N-I+1个数字中最小的与第I个数字交换位置。

程序如下:

varn:

array[1..10]ofinteger;

i,j,k,t,min:

integer;

begin

fori:

=1to10doread(n[i]);

fori:

=1to9dobegin

min:

=30000;

forj:

=ito10dobegin{在第I到第10个数中找到最小的一个}

ifn[j]

min:

=n[j];

k:

=j;{记录该位置}

end;

end;

t:

=n[i];

n[i]:

=n[k];

n[k]:

=t;

end;

fori:

=1to10dowrite(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。

详细过程举例如下:

原序:

[265371611159154819]

一:

[19515111]26[59614837]

二:

[115151]1926[59614837]

三:

[15]11[15]1926[59614837]

四:

1511[15]1926[59614837]

五:

1511151926[59614837]

六:

1511151926[3748]59[61]

七:

1511151926374859[61]

八:

151115192637485961

快速排序法是所有排序方法中速度最快、效率最高的方法。

程序如下:

varn:

array[1..10]ofinteger;

a:

integer;

proceduredg(x,y:

integer);{X,Y表示集合的左右边界,即把第X到第Y个数进行排序}

vari,j,b,c,d,e,f,k:

integer;

begin

k:

=n[x];{标准数}

i:

=x;{I,J为指针}

j:

=y;

repeat

j:

=j+1;

repeat{从J往左找到一个n[j]<=k}

j:

=j-1;

until(n[j]<=k)or(i>j);

ifi<=jthenbegin

b:

=n[i];{交换}

n[i]:

=n[j];

n[j]:

=b;

i:

=i+1;{左指针右移}

end;

i:

=i-1;

repeat{从I往右找到一个n[i]>=k}

i:

=i+1;

until(n[i]>=k)or(i>j);

ifi<=jthenbegin

b:

=n[i];{交换}

n[i]:

=n[j];

n[j]:

=b;

j:

=j-1;

end;

untili>j;

ifj-x>0thendg(x,j);{如果集合中不止一个数则进入下一层递归,X,J为新边界}

ify-i>0thendg(i,y);{如果集合中不止一个数则进入下一层递归,I,Y为新边界}

end;

begin

fora:

=1to10doread(n[a]);

dg(1,10);

fora:

=1to10dowrite(n[a]:

4);

end.

 

三、数论问题

1、设有一块1X1正方形钢板,现需将它分成N个小正方形的钢板。

例如:

输出格式例:

0.25X0.25:

7

0.75X0.75:

1(表示分割成0.25X0.25的正方形7个,0.75X0.751个)

分析:

(1)将一个正方形分成4个,则可增加3个正方形。

(2)以6、7、8个正方形时为基础,则可得到增加的结果:

678

91011

121314

…………

因此由上述递增关系可推得一个递归关系。

2、在平面上有N条直线,且无三线共点,问这些直线能组成多少种不同的交点数。

例如:

分析:

(1)N条无三条直线交于一点的直线最多可能有Cn2个交点,即1/2*N*(N-1)个交点。

(2)对于N条直线,如果N条全部平行,则交点数为0;

如果一条不平行,则交点数为N-1;

如果有两条不与其它平行,则有两种情况,一种这两条直线平行,则交点有(N-2)*2;一种是这两条直线不平行,则交点有(N-2)*2+1。

(3)由上述可知:

N条直线如果有R条直线平行,相当于(N-R)条直线的各种情况再加上R*(N-R)个交点。

也就是说:

我们已知:

2条直线的交点情况是:

0,1;

3条直线的交点情况是:

0,2,3;

4条直线的交点情况可分为:

(1)4条直线平行,0个交点;

(2)3条直线平行,1条直线的情况+3*1=3个交点;(3)2条直线平行,2条直线的情况+2*2个交点,也就是有0+4,1+4两种情况;(4)1条直线平行,3条直线的情况+1*3,也就是有3,5,6三种情况。

综合上述分析,可知:

4条直线的交点情况有:

0,3,4,5,6五种情况。

也就是说,要计算N条直线的情况,应先计算N-1、N-2、……、2条直线的情况。

我们可以用数组来存放2、3、……N条直线的各种情况。

3、哈夫曼编码:

给定一个字符串(假定全由26个小写字母中的前若干个字母组成,总长度不超过50个字符),对字符串每个字符进行编码,编码原则如下:

(1)只能用0,1字符串对字符进行编码;

(2)要求根据编码识别字符串时不会出现混乱、无法识别的情况;

(3)要求字符串编码后的总长度最短。

例如:

对于字符串:

abbabcdefcdabeg,其编码方式可以如下:

a-000,b-001,c-010,d-011,e-100,f-101,g-110

这时总长度为45。

但其编码方式也可以如下:

a-01,b-00,c-100,d-101,e-110,f-1110,g-1111

这时总长度为42。

分析:

(1)字符串中共有多少个不同的字符,以及每个字符出现的次数。

毫无疑问,要使总长度最小,出现次数越多的字符的编码应该越短。

(2)位数少的编码与位数多的编码如何才能不混乱呢?

应该从左边前若干位进行区别。

例如,编码有一个为“0”时,就不能出现“00”,“01”,“001”,“010”等等编码。

当编码中有一个为10时,就不能出现100,101,1000等编码。

四、递归

这里我们将再一次讨论PASCAL语言的递归算法设计方法。

一般的,用BASIC语言实现递归是非常困难的,而用PASCAL语言的自定义函数或过程来实现就要方便、快捷的多,这就是为什么在信息学竞赛中同学们广泛使用PASCAL语言的原因。

我们已经学习自定义函数、过程的编写以及递归的实现方法,这里再简单重复一下。

递归函数

递归函数是PASCAL语言编程中通向高级算法的必由之路,要掌握递归函数必须要先掌握递归这个概念。

什么是递归呢?

我们来看一个例题,在此之前我们先学会什么是数列。

数列即一序列数的总称,如:

1,2,3,4,5,6,7,8……是自然数数列;2,4,6,8,10,……是自然偶数数列;象这种以某种关系定义的数的序列就叫数列。

数列的名称可任取,象上述第一个数列如果名为A,第二个数列名为B,则第一个数列的各个数字的名字就为:

A1,A2,A3,A4……或A

(1),A

(2),A(3)……。

数列A的数字关系是:

(1)A(N)=A(N-1)+1(N>1);

(2)A

(1)=1;由此两个关系,我们只要知道该数列中任何一个数的序号,就可推知该数的数值。

那么如果对于数列A,我想知道A(100)是多少该如何推算呢?

由上述关系我们已经知道:

A(100)=A(99)+1,即要知道A(100),我们就必须先知道A(99);而

A(99)=A(98)+1;即要知道A(99)就必须先知道A(98);由此类推

A(98)=A(97)+1;

………………

A(3)=A

(2)+1;

A

(2)=A

(1)+1;而此时就

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 合同协议

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1