信息学奥赛算法入门教程.docx

上传人:b****7 文档编号:9630599 上传时间:2023-02-05 格式:DOCX 页数:50 大小:74.03KB
下载 相关 举报
信息学奥赛算法入门教程.docx_第1页
第1页 / 共50页
信息学奥赛算法入门教程.docx_第2页
第2页 / 共50页
信息学奥赛算法入门教程.docx_第3页
第3页 / 共50页
信息学奥赛算法入门教程.docx_第4页
第4页 / 共50页
信息学奥赛算法入门教程.docx_第5页
第5页 / 共50页
点击查看更多>>
下载资源
资源描述

信息学奥赛算法入门教程.docx

《信息学奥赛算法入门教程.docx》由会员分享,可在线阅读,更多相关《信息学奥赛算法入门教程.docx(50页珍藏版)》请在冰豆网上搜索。

信息学奥赛算法入门教程.docx

信息学奥赛算法入门教程

全国青少年信息学奥林匹克联赛

算法讲义

 

算法基础篇1

算法具有五个特征:

2

信息学奥赛中的基本算法(枚举法)4

采用枚举算法解题的基本思路:

4

枚举算法应用4

信息学奥赛中的基本算法(回溯法)7

回溯基本思想7

信息学奥赛中的基本算法(递归算法)10

递归算法的定义:

10

递归算法应用10

算法在信息学奥赛中的应用(递推法)13

递推法应用14

算法在信息学奥赛中的应用(分治法)17

分治法应用18

信息学奥赛中的基本算法(贪心法)20

贪心法应用21

算法在信息学奥赛中的应用(搜索法一)24

搜索算法应用24

算法在信息学奥赛中的应用(搜索法二)28

广度优先算法应用29

算法在信息学奥赛中的应用(动态规划法)32

动态规划算法应用33

 

算法基础篇

学习过程序设计的人对算法这个词并不陌生,从广义上讲,算法是指为解决一个问题而采用的方法和步骤;从程序计设的角度上讲,算法是指利用程序设计语言的各种语句,为解决特定的问题而构成的各种逻辑组合。

我们在编写程序的过程就是在实施某种算法,因此程序设计的实质就是用计算机语言构造解决问题的算法。

算法是程序设计的灵魂,一个好的程序必须有一个好的算法,一个没有有效算法的程序就像一个没有灵魂的躯体。

算法具有五个特征:

1、有穷性:

一个算法应包括有限的运算步骤,执行了有穷的操作后将终止运算,不能是个死循环;

2、确切性:

算法的每一步骤必须有确切的定义,读者理解时不会产生二义性。

并且,在任何条件下,算法只有唯一的一条执行路径,对于相同的输入只能得出相同的输出。

如在算法中不允许有“计算8/0”或“将7或8与x相加”之类的运算,因为前者的计算结果是什么不清楚,而后者对于两种可能的运算应做哪一种也不知道。

3、输入:

一个算法有0个或多个输入,以描述运算对象的初始情况,所谓0个输入是指算法本身定义了初始条件。

如在5个数中找出最小的数,则有5个输入。

4、输出:

一个算法有一个或多个输出,以反映对输入数据加工后的结果,这是算法设计的目的。

它们是同输入有着某种特定关系的量。

如上述在5个数中找出最小的数,它的出输出为最小的数。

如果一个程序没有输出,这个程序就毫无意义了;

5、可行性:

算法中每一步运算应该是可行的。

算法原则上能够精确地运行,而且人能用笔和纸做有限次运算后即可完成。

如何来评价一个算法的好坏呢?

主要是从两个方面:

一是看算法运行所占用的时间;我们用时间复杂度来衡量,例如:

在以下3个程序中,

(1)x:

=x+1

(2)fori:

=1tondo

x:

=x+1

(3)fori:

=1tondo

forj:

=1tondo

x:

=x+1

含基本操作“x增1”的语句x:

=x+1的出现的次数分别为1,n和n2则这三个程序段的时间复杂度分别为O

(1),O(n),O(n2),分别称为常量阶、线性阶和平方阶。

在算法时间复杂度的表示中,还有可能出现的有:

对数阶O(logn),指数阶O(2n)等。

在n很大时,不同数量级的时间复杂度有:

O

(1)

二是看算法运行时所占用的空间,既空间复杂度。

由于当今计算机硬件技术发展很快,程序所能支配的自由空间一般比较充分,所以空间复杂度就不如时间复杂度那么重要了,有许多问题人们主要是研究其算法的时间复杂度,而很少讨论它的空间耗费。

时间复杂性和空间复杂性在一定条件下是可以相互转化的。

在中学生信息学奥赛中,对程序的运行时间作出了严格的限制,如果运行时间超出了限定就会判错,因此在设计算法时首先要考虑的是时间因素,必要时可以以牺牲空间来换取时间,动态规划法就是一种以牺牲空间换取时间的有效算法。

对于空间因素,视题目的要求而定,一般可以不作太多的考虑。

我们通过一个简单的数值计算问题,来比较两个不同算法的效率(在这里只比较时间复杂度)。

例:

求N!

所产生的数后面有多少个0(中间的0不计)。

算法一:

从1乘到n,每乘一个数判断一次,若后面有0则去掉后面的0,并记下0的个数。

为了不超出数的表示范围,去掉与生成0无关的数,只保留有效位数,当乘完n次后就得到0的个数。

(pascal程序如下)

var i,t,n,sum:

longint;

begin

 t:

=0;sum:

=1;

readln(n);

 fori:

=1tondo

 begin

 sum:

=sum*i;

 whilesummod10=0do

 begin

 sum:

=sumdiv10;

 inc(t);{计数器增加1}

 end;

 sum:

=summod1000;{舍去与生成0无关的数}

 end;

 writeln(t:

6);

end.

算法二:

此题中生成O的个数只与含5的个数有关,n!

的分解数中含5的个数就等于末尾O的个数,因此问题转化为直接求n!

的分解数中含5的个数。

vart,n:

integer;

begin

 readln(n);

 t:

=0;

 repeat

 n:

=ndiv5;

 inc(t,n);{计数器增加n}

 untiln<5;

 writeln(t:

6);

end.

分析对比两种算法就不难看出,它们的时间复杂度分别为O(N)、O(logN),算法二的执行时间远远小于算法一的执行时间。

在信息学奥赛中,其主要任务就是设计一个有效的算法,去求解所给出的问题。

如果仅仅学会一种程序设计语言,而没学过算法的选手在比赛中是不会取得好的成绩的,选手水平的高低在于能否设计出好的算法。

下面,我们根据全国分区联赛大纲的要求,一起来探讨信息学奥赛中的基本算法。

信息学奥赛中的基本算法(枚举法)

 

枚举法,常常称之为穷举法,是指从可能的集合中一一枚举各个元素,用题目给定的约束条件判定哪些是无用的,哪些是有用的。

能使命题成立者,即为问题的解。

采用枚举算法解题的基本思路:

(1)确定枚举对象、枚举范围和判定条件;

(2)一一枚举可能的解,验证是否是问题的解

下面我们就从枚举算法的的优化、枚举对象的选择以及判定条件的确定,这三个方面来探讨如何用枚举法解题。

枚举算法应用

例1:

百钱买百鸡问题:

有一个人有一百块钱,打算买一百只鸡。

到市场一看,大鸡三块钱一只,小鸡一块钱三只,不大不小的鸡两块钱一只。

现在,请你编一程序,帮他计划一下,怎么样买法,才能刚好用一百块钱买一百只鸡?

算法分析:

此题很显然是用枚举法,我们以三种鸡的个数为枚举对象(分别设为x,y,z),以三种鸡的总数(x+y+z)和买鸡用去的钱的总数(x*3+y*2+z)为判定条件,穷举各种鸡的个数。

下面是解这个百鸡问题的程序

varx,y,z:

integer;

begin

forx:

=0to100do

fory:

=0to100do

forz:

=0to100do{枚举所有可能的解}

if(x+y+z=100)and(x*3+y*2+zdiv3=100)and(zmod3=0)thenwriteln('x=',x,'y=',y,'z=',z);{验证可能的解,并输出符合题目要求的解}

end.

上面的条件还有优化的空间,三种鸡的和是固定的,我们只要枚举二种鸡(x,y),第三种鸡就可以根据约束条件求得(z=100-x-y),这样就缩小了枚举范围,请看下面的程序:

varx,y,z:

integer;

begin

forx:

=0to100do

fory:

=0to100-xdo

begin

z:

=100-x-y;

if(x*3+y*2+zdiv3=100)and(zmod3=0)thenwriteln('x=',x,'y=',y,'z=',z);

end;

end.

未经优化的程序循环了1013次,时间复杂度为O(n3);优化后的程序只循环了(102*101/2)次,时间复杂度为O(n2)。

从上面的对比可以看出,对于枚举算法,加强约束条件,缩小枚举的范围,是程序优化的主要考虑方向。

在枚举算法中,枚举对象的选择也是非常重要的,它直接影响着算法的时间复杂度,选择适当的枚举对象可以获得更高的效率。

如下例:

例2、将1,2...9共9个数分成三组,分别组成三个三位数,且使这三个三位数构成1:

2:

3的比例,试求出所有满足条件的三个三位数.

例如:

三个三位数192,384,576满足以上条件.(NOIP1998pj)

算法分析:

这是1998年全国分区联赛普及组试题(简称NOIP1998pj,以下同)。

此题数据规模不大,可以进行枚举,如果我们不加思地以每一个数位为枚举对象,一位一位地去枚举:

fora:

=1to9do

forb:

=1to9do

………

fori:

=1to9do

这样下去,枚举次数就有99次,如果我们分别设三个数为x,2x,3x,以x为枚举对象,穷举的范围就减少为93,在细节上再进一步优化,枚举范围就更少了。

程序如下:

var

t,x:

integer;

s,st:

string;

c:

char;

begin

forx:

=123to321do{枚举所有可能的解}

begin

t:

=0;

str(x,st);{把整数x转化为字符串,存放在st中}

str(x*2,s);st:

=st+s;

str(x*3,s);st:

=st+s;

forc:

='1'to'9'do{枚举9个字符,判断是否都在st中}

ifpos(c,st)<>0theninc(t)elsebreak;{如果不在st中,则退出循环}

ift=9thenwriteln(x,'',x*2,'',x*3);

end;

end.

在枚举法解题中,判定条件的确定也是很重要的,如果约束条件不对或者不全面,就穷举不出正确的结果, 我们再看看下面的例子。

例3一元三次方程求解(noip2001tg)

问题描述有形如:

ax3+bx2+cx+d=0这样的一个一元三次方程。

给出该方程中各项的系数(a,b,c,d均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间),且根与根之差的绝对值>=1。

要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后2位。

提示:

记方程f(x)=0,若存在2个数x1和x2,且x1

样例

输入:

1-5-420

输出:

-2.002.005.00

算法分析:

由题目的提示很符合二分法求解的原理,所以此题可以用二分法。

用二分法解题相对于枚举法来说很要复杂很多。

此题是否能用枚举法求解呢?

再分析一下题目,根的范围在-100到100之间,结果只要保留两位小数,我们不妨将根的值域扩大100倍(-10000<=x<=10000),再以根为枚举对象,枚举范围是-10000到10000,用原方程式进行一一验证,找出方程的解。

有的同学在比赛中是这样做

var

k:

integer;

a,b,c,d,x:

real;

begin

read(a,b,c,d);

fork:

=-10000to10000do

begin

x:

=k/100;

ifa*x*x*x+b*x*x+c*x+d=0thenwrite(x:

0:

2,'');

end;

end.

用这种方法,很快就可以把程序编出来,再将样例数据代入测试也是对的,等成绩下来才发现这题没有全对,只得了一半的分。

这种解法为什么是错的呢?

错在哪里?

前面的分析好象也没错啊,难道这题不能用枚举法做吗?

看到这里大家可能有点迷惑了。

在上面的解法中,枚举范围和枚举对象都没有错,而是在验证枚举结果时,判定条件用错了。

因为要保留二位小数,所以求出来的解不一定是方程的精确根,再代入ax3+bx2+cx+d中,所得的结果也就不一定等于0,因此用原方程ax3+bx2+cx+d=0作为判断条件是不准确的。

我们换一个角度来思考问题,设f(x)=ax3+bx2+cx+d,若x为方程的根,则根据提示可知,必有f(x-0.005)*(x+0.005)<0,如果我们以此为枚举判定条件,问题就逆刃而解。

另外,如果f(x-0.005)=0,哪么就说明x-0.005是方程的根,这时根据四舍5入,方程的根也为x。

所以我们用(f(x-0.005)*f(x+0.005)<0)和(f(x-0.005)=0)作为判定条件。

为了程序设计的方便,我们设计一个函数f(x)计算ax3+bx2+cx+d的值,程序如下:

{$N+}

var

k:

integer;

a,b,c,d,x:

extended;

functionf(x:

extended):

extended;{计算ax3+bx2+cx+d的值}

begin

f:

=((a*x+b)*x+c)*x+d;

end;

begin

read(a,b,c,d);

fork:

=-10000to10000do

begin

x:

=k/100;

if(f(x-0.005)*f(x+0.005)<0)or(f(x-0.005)=0)thenwrite(x:

0:

2,'');{若x两端的函数值异号或x-0.005刚好是方程的根,则确定x为方程的根}

end;

end.

用枚举法解题的最大的缺点是运算量比较大,解题效率不高,如果枚举范围太大(一般以不超过两百万次为限),在时间上就难以承受。

但枚举算法的思路简单,程序编写和调试方便,比赛时也容易想到,在竞赛中,时间是有限的,我们竞赛的最终目标就是求出问题解,因此,如果题目的规模不是很大,在规定的时间与空间限制内能够求出解,那么我们最好是采用枚举法,而不需太在意是否还有更快的算法,这样可以使你有更多的时间去解答其他难题。

 

信息学奥赛中的基本算法(回溯法)

如果上期的“百钱买百鸡”中鸡的种类数是变化的,用枚举法就无能为力了,这里介绍另一种算法——回溯法。

回溯基本思想

回溯法是一种既带有系统性又带有跳跃性的搜索法,它的基本思想是:

在搜索过程中,当探索到某一步时,发现原先的选择达不到目标,就退回到上一步重新选择。

它主要用来解决一些要经过许多步骤才能完成的,而每个步骤都有若干种可能的分支,为了完成这一过程,需要遵守某些规则,但这些规则又无法用数学公式来描述的一类问题。

下面通过实例来了解回溯法的思想及其在计算机上实现的基本方法。

例1、从N个自然数(1,2,…,n)中选出r个数的所有组合。

算法分析:

设这r个数为a1,a2,…ar,把它们从大到小排列,则满足:

(1)a1>a2>…>ar;

(2)其中第i位数(1<=i<=r)满足ai>r-i;

我们按以上原则先确定第一个数,再逐位生成所有的r个数,如果当前数符合要求,则添加下一个数;否则返回到上一个数,改变上一个数的值再判断是否符合要求,如果符合要求,则继续添加下一个数,否则返回到上一个数,改变上一个数的值……按此规则不断循环搜索,直到找出r个数的组合,这种求解方法就是回溯法。

如果按以上方法生成了第i位数ai,下一步的的处理为:

(1)若ai>r-i且i=r,则输出这r个数并改变ai的值:

ai=ai-1;

(2)若ai>r-i且i≠r,则继续生成下一位ai+1=ai-1;

(3)若ai<=r-i,则回溯到上一位,改变上一位数的值:

ai-1=ai-1-1;

算法实现步骤:

第一步:

输入n,r的值,并初始化;i:

=1;a[1]:

=n;

第二步:

若a[1]>r-1则重复:

若a[i]>r-i,

若i=r,则输出解,并且a[i]:

=a[i]-1;

若i<>r,则继续生成下一位:

a[i+1]:

=a[i]-1;i:

=i+1;

若a[i]<=r-i,则回溯:

i:

=i-1;a[i]:

=a[i]-1;

第三步:

结束;

程序实现

varn,r,i,j:

integer;

a:

array[1..10]ofinteger;

begin

readln(n,r);i:

=1;a[1]:

=n;

repeat

ifa[i]>r-ithen{符合条件}

ifi=rthen{输出}

begin

forj:

=1tordowrite(a[j]:

3);

writeln;

a[i]:

=a[i]-1;

end

else{继续搜索}

begina[i+1]:

=a[i]-1;i:

=i+1;end

else{回溯}

begini:

=i-1;a[i]:

=a[i]-1;end;

untila[1]=r-1;

end.

下面我们再通过另一个例子看看回溯在信息学奥赛中的应用。

例2数的划分(noip2001tg)

问题描述整数n分成k份,且每份不能为空,任意两份不能相同(不考虑顺序)。

例如:

n=7,k=3,下面三种分法被认为是相同的。

1,1,5;1,5,1;5,1,1;

问有多少种不同的分法。

输入:

n,k(6

输出:

一个整数,即不同的分法。

样例

输入:

73

输出:

4{四种分法为:

1,1,5;1,2,4;1,3,3;2,2,3;}

算法分析:

此题可以用回溯法求解,设自然数n拆分为a1,a2,…,ak,必须满足以下两个条件:

(1)n=a1+a2+…+ak;

(2)a1<=a2<=…<=ak(避免重复计算);

现假设己求得的拆分数为a1,a2,…ai,且都满足以上两个条件,设sum=n-a1-a2-…-ai,我们根据不同的情形进行处理:

(1)如果i=k,则得到一个解,则计数器t加1,并回溯到上一步,改变ai-1的值;

(2)如果i=ai,则添加下一个元素ai+1;

(3)如果i

算法实现步骤如下:

第一步:

输入自然数n,k并初始化;t:

=0;i:

=1;a[i]:

=1;sum:

=n-1;nk:

=ndivk;

第二步:

如果a[1]<=nk重复:

若i=k,搜索到一个解,计数器t=t+1;并回溯;

否则:

若sum>=a[i]则继续搜索;

若sum

搜索时,inc(i);a[i]:

=a[i-1];sum:

=sum-a[i];

回溯时,dec(i);inc(a[i]);sum:

=sum+a[i+1]-1;

第三步:

输出。

程序如下:

var

n,nk,sum,i,k:

integer;

t:

longint;

a:

array[1..6]ofinteger;

begin

readln(n,k);

nk:

=ndivk;

t:

=0;i:

=1;a[i]:

=1;sum:

=n-1;{初始化}

repeat

ifi=kthen{判断是否搜索到底}

begininc(t);dec(i);inc(a[i]);sum:

=sum+a[i+1]-1;end{回溯}

elsebegin

ifsum>=a[i]then{判断是否回溯}

begininc(i);a[i]:

=a[i-1];sum:

=sum-a[i];end{继续搜}

elsebegindec(i);inc(a[i]);sum:

=sum+a[i+1]-1;end;{回溯}

end;

untila[1]>nk;

writeln(t);

end.

回溯法是通过尝试和纠正错误来寻找答案,是一种通用解题法,在NOIP中有许多涉及搜索问题的题目都可以用回溯法来求解。

 

信息学奥赛中的基本算法(递归算法)

递归算法的定义:

如果一个对象的描述中包含它本身,我们就称这个对象是递归的,这种用递归来描述的算法称为递归算法。

我们先来看看大家熟知的一个的故事:

从前有座山,山上有座庙,庙里有个老和尚在给小和尚讲故事,他说从前有座山,山上有座庙,庙里有个老和尚在给小和尚讲故事,他说……

上面的故事本身是递归的,用递归算法描述:

procedurebonze-tell-story;

begin

if讲话被打断then故事结束

elsebegin

从前有座山,山上有座庙,庙里有个老和尚在给小和尚讲故事;

bonze-tell-story;

end

end;

从上面的递归事例不难看出,递归算法存在的两个必要条件:

(1)必须有递归的终止条件;

(2)过程的描述中包含它本身;

在设计递归算法中,如何将一个问题转化为递归的问题,是初学者面临的难题,下面我们通过分析汉诺塔问题,看看如何用递归算法来求解问题;

递归算法应用

例1:

汉诺塔问题,如下图,有A、B、C三根柱子。

A柱子上按从小到大的顺序堆放了N个盘子,现在要把全部盘子从A柱移动到C柱,移动过程中可以借助B柱。

移动时有如下要求:

(1)一次只能移动一个盘子;

(2)不允许把大盘放在小盘上边;

(3)盘子只能放在三根柱子上;

算法分析:

当盘子比较多的时,问题比较复杂,所以我们先分析简单的情况:

如果只有一个盘子,只需一步,直接把它从A柱移动到C柱;

如果是二个盘子,共需要移动3步:

(1)把A柱上的小盘子移动到B柱;

(2)把A柱上的大盘子移动到C柱;

(3)把B柱上的大盘子移动到C柱;

如果N比较大时,需要很多步才能完成,我们先考虑是否能把复杂的移动过程转化为简单的移动过程,如果要把A柱上最大的盘子移动到C柱上去,必须先把上面的N-1个盘子从A柱移动到B柱上暂存,按这种思路,就可以把N个盘子的移动过程分作3大步:

(1)把A柱上面的N-1个盘子移动到B柱;

(2)把A柱上剩下的一个盘子移动到C柱;

(3)把B柱上面的N-1个盘子移动到C柱;

其中N-1个盘子的移动过程又可按同样的方法分为三大步,这样就把移动过程转化为一个递归的过程,直到最后只剩下一个盘子,按照移动一个盘子的方法移动,递归结束。

递归过程:

procedureHanoi(N,A,B,C:

integer;);{以B柱为中转柱将N个盘子从A柱移动到C柱}

begin

ifN=1thenwrite(A,’->’,C){把盘子直接从A移动到C}

elsebegin

Hanoi(N-1,A,C,B);{以C柱为中转柱将N-1个盘子从A柱移动到B柱}

write(A,’->’,C);{把剩下的一个盘子从A移动到C}

Hanoi(N-1,B,A,C);{以A柱为中转柱将N-1个盘子从B柱移动到C柱}

end;

end;

从上面的例子我们可以看出,在使用递归算法时,首先弄清楚简单情况下的解法,然后弄清楚如何把复杂情况归纳为更简单的情况。

在信息学奥赛中有的问题的结构或所处理的数据本身是递归定义的,这样的问题非常适合用递归算法来求解,对于这类问题,我们把它分解为具有相同性质的若干个子问题,如果子问题解决了,原问题也就解决了。

例2求先序排列(NOIP2001pj)

[问题描述]给出一棵二叉树的中序与后序排列。

求出它的先序排列。

(约定树结点用不同的大写字母表示,长度≤8)。

[样例]输入

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

当前位置:首页 > 党团工作 > 入党转正申请

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

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