1、信息学奥赛中的基本算法,一、枚举法,一、算法相关知识,从广义上讲,算法是指为解决一个问题而采用的方法和步骤 。 从程序计设的角度上讲,算法是指利用程序设计语言的各种语句,为解决特定的问题而构成的各种逻辑组合。 程序设计的实质就是用计算机语言构造解决问题的算法。算法是程序设计的灵魂 。,算法的基本特征,有穷性: 一个算法应包括有限的运算步骤,执行了有穷的操作后将终止运算,不能是个死循环; 确切性: 算法的每一步骤必须有确切的定义,读者理解时不会产生二义性。并且,在任何条件下,算法只有唯一的一条执行路径,对于相同的输入只能得出相同的输出。如在算法中不允许有“计算8/0”或“将7或8与x相加”之类的
2、运算,因为前者的计算结果是什么不清楚,而后者对于两种可能的运算应做哪一种也不知道。 输入:一个算法有0个或多个输入,以描述运算对象的初始情况,所谓0个输入是指算法本身定义了初始条件。如在5个数中找出最小的数,则有5个输入。 输出:一个算法有一个或多个输出,以反映对输入数据加工后的结果,这是算法设计的目的。它们是同输入有着某种特定关系的量。如上述在5个数中找出最小的数,它的输出为最小的数。如果一个程序没有输出,这个程序就毫无意义了; 可行性: 算法中每一步运算应该是可行的。算法原则上能够精确地运行,而且人能用笔和纸做有限次运算后即可完成。,如何评价算法的好坏?,时间复杂度:算法运行所占用的时间
3、空间复杂度:算法运行时所占用的空间 信息学奥赛中,对程序的运行时间作出了严格的限制,如果运行时间超出了限定就会判错,因此在设计算法时首先要考虑的是时间因素,必要时可以以牺牲空间来换取时间,1.for i:=1 to 100 do for j:=1 to 100 do si,j:=0;执行次数100*100次,时间复杂度O(1) 2.for i:=1 to n do for j:=1 to 200 do si,j:=0;执行次数n*200次,时间复杂度O(n) 3.for i:=1 to n do for j:=1 to n div 2 do si,j:=0;执行次数n*n/2次,时间复杂度O(
4、n2) 4.for i:=1 to n do for j:=1 to n-1 do for k:=1 to n-2 do si,j,k:=0;执行次数n*(n-1)*(n-2)次,时间复杂度O(n3),时间复杂度怎么算?,5.for i:=1 to n do begin for j:=1 to n do si,j,0:=0; for j:=1 to n do for k:=1 to n dosi,j,k:=1; end; 执行次数n*(n+n*n)次,时间复杂度O(n3),按数量级递增排列,常见的时间复杂度有: 常数阶O(1) 对数阶O(logn) 线性阶O(n), 线性对数阶O(nlogn)
5、 平方阶O(n2) 立方阶O(n3) . k次方阶O(nk), 指数阶O(2n),用例子说明一下改进算法对降低时间复杂度的好处。 例:求N!所产生的数后面有多少个0(中间的0不计),算法一:从1乘到n,每乘一个数判断一次,若后面有0则去掉后面的0,并记下0的个数。为了不超出数的表示范围,去掉与生成0无关的数,只保留有效位数,当乘完n次后就得到0的个数。var i,t,n,sum:longint; begint:=0; sum:=1;readln(n);for i:=1 to n dobegin,sum:=sum*i;while sum mod 10=0 dobeginsum:=sum div
6、10;inc(t);计数器增加1end;sum:=sum mod 1000;舍去与生成0无关的数end;writeln(t:6); end.,时间复杂度为O(N),例:求N!所产生的数后面有多少个0(中间的0不计),算法二:此题中生成0的个数只与含5的个数有关,n!的分解数中含5的个数就等于末尾0的个数,因此问题转化为直接求n!的分解数中含5的个数。 var t,n:integer; begin,readln(n);t:=0; repeatn:=n div 5 ;inc(t,n); 计数器增加nuntil n5;writeln(t:6); end.,时间复杂度为O(logN),在程序设计中,我
7、们经常需要根据给定的一组条件求满足条件的解。如果问题的解可以用公式,或者按一定的规则、规律求出,那么就可以很容易地写出相应的程序。但是对于许多问题,我们都难以找到明确的公式和计算规则,在这种情况下,我们可以利用计算机高速运算的特点,用穷举法来求解。,枚举法(穷举法),基本思想:穷举也叫枚举,它的基本思想是先依据题目的部分条件将所有可能解列举出来,然后用其余的条件对所有可能解进行一一验证,删去那些不符合条件的解,剩下符合条件的解就是整个问题的解。,适用枚举法求解的问题必须满足两个条件:1、可事先确定解元素的个数n;2、解变量,n的可能值为一个连续的值域。,例1:百钱买百鸡问题:有一个人有一百块钱
8、,打算买一百只鸡。到市场一看,大鸡三块钱一只,小鸡一块钱三只,不大不小的鸡两块钱一只。现在,请你编一程序,帮他计划一下,怎么样买法,才能刚好用一百块钱买一百只鸡?,算法分析:此题很显然是用枚举法,我们以三种鸡的个数为枚举对象(分别设为x,y,z),以三种鸡的总数(x+y+z)和买鸡用去的钱的总数(x*3+y*2+z)为判定条件,穷举各种鸡的个数。,程序一: var x,y,z:integer; begin for x:=0 to 100 dofor y:=0 to 100 dofor z:=0 to 100 do枚举所有可能的解if (x+y+z=100)and(x*3+y*2+z div 3
9、=100)and(z mod 3=0)then writeln(x=,x,y=,y,z=,z); 验证可能的解,并输出符合题目要求的解 end.,改进后: var x,y,z:integer; beginfor x:=0 to 33 dofor y:=0 to 50 dobeginz:=100-x-y;if (x*3+y*2+z div 3=100)and(z mod 3=0)then writeln(x=,x,y=,y,z=,z);end; end.,例2、猜算式,设有下列的除法算式:请根据上述算式中的信息求出被除数和除数。,其它信息:设除数为x,被除数为y,则10=100。,我们不可能对1
10、4个格子中的数都进行枚举,本题的关键在于找出适当的元素进行枚举。,本题已给出了商和余数,只要再知道被除数或除数,就可确定整个算式。枚举除数枚举量较小,我们选择枚举除数,而被除数则可按公式y=809*x+1计算得出。,varx,y:integer; beginfor x:=10 to 99 dobeginy:=( ); 计算出被除数if y9999 then break;优化语句if ( )then writeln(y, ,x);end; end. 运行结果: 9709 12,枚举所有可能的除数,验证,穷举法是一种比较笨拙的算法,因为它需要列举出许多个可能解来一一验证,程序往往需要运行很长时间,
11、效率较低。 针对穷举法效率较低的缺点,在设计穷举算法时,我们必须注意以下二点:减少枚举变量:充分挖掘各解元素之间的联系,将一些非枚举不可的解元素列为枚举变量,然后在此基础上直接计算出其它解元素的可能值。减少枚举变量的值域:枚举前要尽可能多地将不符合条件的情况预先排除。,809*x+1,(y=1000) and (8*x=100),例3、将1,2.9共9个数分成三组,分别组成三个三位数,且使这三个三位数构成1:2:3的比例,试求出所有满足条件的三个三位数. 例如:三个三位数192,384,576满足以上条件.,算法分析:此题数据规模不大,可以进行枚举,如果我们不加思地以每一个数位为枚举对象,一位
12、一位地去枚举: for a:=1 to 9 do for b:=1 to 9 do for i:=1 to 9 do 这样下去,枚举次数就有9次,如果我们分别设三个数为x,2x,3x,以x为枚举对象,穷举的范围就减少为,在细节上再进一步优化,枚举范围就更少了。,vart,x:integer;s,st:string;c:char; beginfor x:=123 to 321 do枚举所有可能的解begint:=0;str(x,st);把整数x转化为字符串,存放在st中str(x*2,s);,st:=st+s;str(x*3,s);st:=st+s; for c:=1 to 9 do枚举9个字符
13、,判断是否都在st中if pos(c,st)0 then inc(t) else break;如果不在st中,则退出循环 if t=9 then writeln(x, ,x*2, ,x*3);end; end.,例4:方格填数,如下图所示的八个格子中填入1至8八个数字,使得相邻的和对角线的数字之差不为1。请编程找出所有放法。,分析:由题意可知,放入b3,b6这两个格子中的数,必须和六个数不连续,仅可以和一个数是连续的,这样的数只能是1和8。因此,b1,b3,b6,b8这四个格子中数的放法可以先确定下来:2,8,1,7或7,1,8,2。接着,我们只需枚举b2、b4、b5三个变量,范围都是3至6,
14、而b7可通过计算来得到。(1,2),(1,4),(2,5),(4,7),(5,8),(7,8)共6对格子中的数需要验证。,const link:array16,12 of integer=(1,2),(1,4),(2,5),(4,7),(5,8),(7,8); var b:array18 of integer;存放摆放方案 procedure print; 输出一种满足条件的放法beginwriteln(b1:4);writeln(b2:2,b3:2,b4:2);writeln(b5:2,b6:2,b7:2);writeln(b8:4);writeln;end; function choose
15、:boolean; 检验当前放法是否符合要求var i:integer;beginchoose:=false;for i:=1 to 6 doif abs( blinki,1 - blinki,2 )=1 then exit;choose:=true;end;,procedure try; var b2,b4,b5,b7:integer;beginfor b2:=3 to 6 do 枚举b2,b4,b5,计算b7for b4:=3 to 6 doif b2b4 thenfor b5:=3 to 6 doif (b5b2)and(b5b4) thenbeginb7:=18-b2-b4-b5;b2:=b2;b4:=b4;b5:=b5;b7:=b7;if choose then print;end;end;,beginb1:=2; b3:=8; b6:=1; b8:=7;情况一try;b1:=7; b3:=1; b6:=8; b8:=2;情况二try;readln; end.,枚举法的优点由于枚举算法一般是现实生活中问题的“直译”,因此比较直观,易于理解;由于枚举算法建立在考察大量状态、甚至是穷举所有状态的基础上,所以算法的正确性比较容易证明。,枚举法的缺点 枚举算法的效率取决于枚举状态的数量以及单个状态枚举的代价,因此效率比较低。,枚举法的优缺点,