高中信息技术 全国青少年奥林匹克联赛教案 枚举法二.docx

上传人:b****5 文档编号:3423386 上传时间:2022-11-22 格式:DOCX 页数:21 大小:80.32KB
下载 相关 举报
高中信息技术 全国青少年奥林匹克联赛教案 枚举法二.docx_第1页
第1页 / 共21页
高中信息技术 全国青少年奥林匹克联赛教案 枚举法二.docx_第2页
第2页 / 共21页
高中信息技术 全国青少年奥林匹克联赛教案 枚举法二.docx_第3页
第3页 / 共21页
高中信息技术 全国青少年奥林匹克联赛教案 枚举法二.docx_第4页
第4页 / 共21页
高中信息技术 全国青少年奥林匹克联赛教案 枚举法二.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

高中信息技术 全国青少年奥林匹克联赛教案 枚举法二.docx

《高中信息技术 全国青少年奥林匹克联赛教案 枚举法二.docx》由会员分享,可在线阅读,更多相关《高中信息技术 全国青少年奥林匹克联赛教案 枚举法二.docx(21页珍藏版)》请在冰豆网上搜索。

高中信息技术 全国青少年奥林匹克联赛教案 枚举法二.docx

高中信息技术全国青少年奥林匹克联赛教案枚举法二

枚举法

课题:

枚举法

目标:

知识目标:

枚举算法的本质和应用

能力目标:

枚举算法的应用!

重点:

利用枚举算法解决实际问题

难点:

枚举算法的次数确定

板书示意:

1)简单枚举(例7、例8、例9)

2)利用枚举解决逻辑判断问题(例10、例11)

3)枚举解决竞赛问题(例12、例13、例14)

授课过程:

所谓枚举法,指的是从可能的解集合中一一枚举各元素,用题目给定的检验条件判定哪些是无用的,哪些是有用的.能使命题成立,即为其解。

一般思路:

●对命题建立正确的数学模型;

●根据命题确定的数学模型中各变量的变化范围(即可能解的范围);

●利用循环语句、条件判断语句逐步求解或证明;

枚举法的特点是算法简单,但有时运算量大。

对于可能确定解的值域又一时找不到其他更好的算法时可以采用枚举法。

例7:

求满足表达式A+B=C的所有整数解,其中A,B,C为1~3之间的整数。

分析:

本题非常简单,即枚举所有情况,符合表达式即可。

算法如下:

forA:

=1to3do

forB:

=1to3do

forC:

=1to3do

ifA+B=Cthen

Writeln(A,‘+’,B,‘=’,C);

上例采用的就是枚举法。

所谓枚举法,指的是从可能的解的集合中一一枚举各元素,用题目给定的检验条件判定哪些是无用的,哪些是有用的。

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

从枚举法的定义可以看出,枚举法本质上属于搜索。

但与隐式图的搜索有所区别,在采用枚举法求解的问题时,必须满足两个条件:

1预先确定解的个数n;

2对每个解变量A1,A2,……,An的取值,其变化范围需预先确定

A1∈{X11,……,X1p}

……

Ai∈{Xi1,……,Xiq}

……

An∈{Xn1,……,Xnk}

例7中的解变量有3个:

A,B,C。

其中

A解变量值的可能取值范围A∈{1,2,3}

B解变量值的可能取值范围B∈{1,2,3}

C解变量值的可能取值范围C∈{1,2,3}

则问题的可能解有27个

(A,B,C)∈{(1,1,1),(1,1,2),(1,1,3),

1,2,1),(1,2,2),(1,2,3),

………………………………

(3,3,1),(3,3,2),(

3,3,3)}

在上述可能解集合中,满足题目给定的检验条件的解元素,即为问题的解。

如果我们无法预先确定解的个数或各解的值域,则不能用枚举,只能采用搜索等算法求解。

由于回溯法在搜索每个可能解的枚举次数一般不止一次,因此,对于同样规模的问题,回溯算法要比枚举法时间复杂度稍高。

例8给定一个二元一次方程aX+bY=c。

从键盘输入a,b,c的数值,求X在[0,100],Y在[0,100]范围内的所有整数解。

分析:

要求方程的在一个范围内的解,只要对这个范围内的所有整数点进行枚举,看这些点是否满足方程即可。

参考程序:

programexam8;

var

a,b,c:

integer;

x,y:

integer;

begin

write('Inputa,b,c:

');readln(a,b,c);

forx:

=0to100do

fory:

=0to100do

ifa*x+b*y=cthenwriteln(x,'',y);

end.

从上例可以看出,所谓枚举法,指的是从可能的解集合中一一枚举各元素,用题目给定的检验条件判定哪些是无用的,哪些是有用的.能使命题成立,即为其解。

例9巧妙填数

1

9

2

3

8

4

5

7

6

将1~9这九个数字填入九个空格中。

每一横行的三个数字组成一个三位数。

如果要使第二行的三位数是第一行的两倍,第三行的三位数是第一行的三倍,应怎样填数。

如图6:

 

图6

分析:

本题目有9个格子,要求填数,如果不考虑问题给出的条件,共有9!

=362880种方案,在这些方案中符合问题条件的即为解。

因此可以采用枚举法。

但仔细分析问题,显然第一行的数不会超过400,实际上只要确定第一行的数就可以根据条件算出其他两行的数了。

这样仅需枚举400次。

因此设计参考程序:

programexam9;

var

i,j,k,s:

integer;

functionsum(s:

integer):

integer;

begin

sum:

=sdiv100+sdiv10mod10+smod10

end;

functionmul(s:

integer):

longint;

begin

mul:

=(sdiv100)*(sdiv10mod10)*(smod10)

end;

begin

fori:

=1to3do

forj:

=1to9do

ifj<>ithenfork:

=1to9do

if(k<>j)and(k<>i)thenbegin

s:

=i*100+j*10+k;{求第一行数}

if3*s<1000then

if(sum(s)+sum(2*s)+sum(3*s)=45)and

(mul(s)*mul(2*s)*mul(3*s)=362880)then{满足条件,并数字都由1~9

组成}

begin

writeln(s);

writeln(2*s);

writeln(3*s);

writeln;

end;

end;

end.

例10在某次数学竞赛中,A、B、C、D、E五名学生被取为前五名。

请据下列说法判断出他们的具体名次,即谁是第几名?

条件1:

你如果认为A,B,C,D,E就是这些人的第一至第五名的名次排列,便大错。

因为:

没猜对任何一个优胜者的名次。

也没猜对任何一对名次相邻的学生。

条件2:

你如果按D,A,E,C,B来排列五人名次的话,其结果是:

说对了其中两个人的名次。

还猜中了两对名次相邻的学生的名次顺序。

分析:

本题是一个逻辑判断题,一般的逻辑判断题都采用枚举法进行解决。

5个人的名次分别可以有5!

=120种排列可能,因为120比较小,因此我们对每种情况进行枚举,然后根据条件判断哪些符合问题的要求。

根据已知条件,A<>1,B<>2,C<>3,D<>4,E<>5,因此排除了一种可能性,只有4!

=24种情况了。

参考程序:

ProgramExam10;

Var

A,B,C,D,E:

Integer;

Cr:

Array[1..5]OfChar;

Begin

ForA:

=1To5Do

ForB:

=1To5Do

ForC:

=1To5Do

ForD:

=1To5Do

ForE:

=1To5DoBegin

{ABCDE没猜对一个人的名次}

If(A=1)Or(B=2)Or(C=3)Or(D=4)Or(E=5)ThenContinue;

If[A,B,C,D,E]<>[1,2,3,4,5]ThenContinue;{他们名次互不重复}

{DAECB猜对了两个人的名次}

IfOrd(A=2)+Ord(B=5)+Ord(C=4)+Ord(D=1)+Ord(E=3)<>2ThenContinue;

{ABCDE没猜对一对相邻名次}

If(B=A+1)Or(C=B+1)Or(D=C+1)Or(E=D+1)ThenContinue;

{DAECB猜对了两对相邻人名次}

IfOrd(A=D+1)+Ord(E=A+1)+Ord(C=E+1)+Ord(B=C+1)<>2ThenContinue;

Cr[A]

:

='A';Cr[B]:

='B';Cr[C]:

='C';

Cr[D]:

='D';Cr[E]:

='E';

Writeln(Cr[1],'',Cr[2],'',Cr[3],'',Cr[4],'',Cr[5]);

End;

End.

例11:

来自不同国家的四位留学生A,B,C,D在一起交谈,他们只会中、英、法、日四种语言中的2种,情况是,没有人既会日语又会法语;A会日语,但D不会,A和D能互相交谈,B不会英语,但A和C交谈时却要B当翻译,B,C,D三个想互相交谈,但找不到共同的语言,只有一种语言3人都会,编程确定A,B,C,D四位留学生各会哪两种语言。

分析:

将中、法、日、英四种语言分别定义为CHN、FRH、JPN、ENG,则四种语言中取两种共有(CHN,ENG),(CHN,FRH),(CHN,JPN),(ENG,FRH),(ENG,JPN),(FRH,JPN)六种组合,分别定义为1、2、3、4、5、6。

据已知,没有人既会日语又会法语;因此,组合6不会出现;A会日语,所以A只可能等于3、5;D不会日语,所以D只可能等于1、2、4;B不会英语,所以B只可能等于2、3;见下表。

果我们对A、B、C、D分别进行枚举,根据判定条件,即可找到答案。

(CHN,ENG)

(CHN,FRH)

(CHN,JPN)

(ENG,FRH)

(ENG,JPN)

A

×

×

×

B

×

×

×

C

D

×

×

程序如下:

programEXAM11;

type

Language=(CHN,ENG,FRH,JPN);

TNoSet=setofLanguage;

const

No:

array[1..5]ofTNoSet=

([CHN,ENG],[CHN,FRH],[CHN,JPN],[ENG,FRH],[ENG,JPN]);

 

var

A,B,C,D:

1..5;

Can

1,Can2,Can3,Can4:

Boolean;

functionMight(Lang:

Language):

Boolean;

var

Bool:

Boolean;

begin

Bool:

=false;

ifNo[A]*No[A]*No[C]=[Lang]thenBool:

=True;

ifNo[A]*No[B]*No[D]=[Lang]thenBool:

=True;

ifNo[A]*No[C]*No[D]=[Lang]thenBool:

=True;

ifNo[B]*No[C]*No[D]=[Lang]thenBool:

=True;

Might:

=Bool

end;

procedurePrint(A,B,C,D:

Integer);

procedureShow(P:

Integer;Ch:

Char);

var

I:

Integer;

Lang:

Language;

begin

Write(ch,':

');

forLang:

=CHNtoJPNdo

ifLanginNo[P]then

caseLangof

CHN:

Write('CHN':

5);

FRH:

Write('FRH':

5);

JPN:

Write('JPN':

5);

ENG:

Write('ENG':

5);

end;

Writeln;

end;

begin

Show(A,'A');

Show(B,'B');

Show(C,'C');

Show(D,'D');

end;

begin

forA:

=3to5do

ifA<>4thenforB:

=2to3do

forC:

=1to5do

forD:

=1to4doifD<>3thenbegin

{A和D能互相交谈}

Can1:

=No[A]*No[D]<>[];

{A和C交谈时却要B当翻译}

Can2:

=(No[A]*No[C]=[])and(No[A]*No[B]<>[])

and(No[B]*No[C]<>[]);

{B,C,D三个想互相交谈,但找不到共同的语言}

Can3:

=No[B]*No

[C]*No[D]=[];

{只有一种语言3人都会}

Can4:

=Ord(Might(CHN))+Ord(Might(ENG))

+Ord(Might

(FRH))+Ord(Might(JPN))=1;

ifCan1andCan2andCan3andCan4thenPrint(A,B,C,D);

end;

end.

例12古纸残篇

在一位数学家的藏书

中夹有一张古旧的纸片。

纸片上的字早已模糊不清了,只留下曾经写过字的痕迹,依稀还可以看出它是一个乘法算式,如图7所示。

这个算式上原来的数字是什么呢?

夹着这张纸片的书页上,“素数”两个字被醒目的划了出来。

难道说,这个算式与素数有什么关系吗?

有人对此作了深入的研究,果然发现这个算式中的每一个数字都是

***

×**

****

****

*****

图7

素数,而且这样的算式是唯一的。

请你也研究一番,并把这个算式写出来。

分析:

实际上,只要知道乘数和被乘数就可以写出乘法算式,所以我们可以枚举乘数与被乘数的每一位。

然后再判断是不是满足条件即可。

计算量是45=1024,对于计算机来说,计算量非常小。

参考程序:

ProgramExam12;

Const

Su:

Array[1..4]OfLongint=(2,3,5,7);

Var

A1,A2,A3,B1,B2,X,Y,S:

Longint;

FunctionKx(S:

Longint):

Boolean;{判断一个数

是不是都是由素数组成}

Begin

Kx:

=True;

WhileS<>0DoBegin

IfNot((SMod10)In[2,3,5,7])ThenBegin

Kx:

=False;

Exit;

End;

S:

=SDiv10;

End;

End;

Begin

ForA1:

=1To4Do

ForA2:

=1To4Do

ForA3:

=1To4Do

ForB1:

=1To4Do

ForB2:

=1To4DoBegin

X:

=Su[A1]*100+Su[A2]*10+Su[A3];{X为被乘数}

IfX*Su[B1]<1000ThenContinue;

IfX*Su[B2]<1000ThenContinue;

IfX*(Su[B1]*10+Su[B2])<10000ThenContinue;

{它们分别是两个四位数,一个五位数}

If(Kx(X*Su[B1])=False)Or

(Kx(X*Su[B2])=False)Or

(Kx(X*(Su[B1]*10+Su[B2]))=False)ThenContinue;

{满足其他数都是由质数构成}

Writeln('',Su[A1],Su[A2],Su[A3]);

Writeln('*',Su[B1],Su[B2]);

Writeln('-----------');

Writeln('',X*Su[B2]);

Writeln('',X*Su[B1]);

Writeln('-----------');

Writeln('',X*(Su[B1]*10+Su[B2]));

End;

End.

例13:

时钟问题(IOI94-4)

在图8所示的3*3矩阵中有9个时钟,我们的目标是旋转时钟指针,使所有时钟的指针都指向12点。

允许旋转时钟指针的方法有9种,每一种移动用一个数字号(1,2,…,9)表示。

图2-11示出9个数字号与相应的受控制的时钟,这些时钟在图中以灰色标出,其指针将顺时针旋转90度。

输入数据:

由输入文件INPUT.TXT读9个数码,这些数码给出了9个时钟时针的初始位置。

数码与时刻的对应关系为:

0——12点

1——3点

2——6点

3——9点

图2-11中的例子对应下列输入数据:

330

222

212

输出数据:

将一个最短的移动序列(数字序列)写入输出文件OUTPUT.TXT中,该序列要使所有的时钟指针指向12点,若有等价的多个解,仅需给出其中一个。

在我们的例子中,相应的OUTPUT.TXT的内容为:

5849

输入输出示例:

INPUT.TXT

OUTPUT.TXT

330

222

212

5489

具体的移动

方案如图10所示。

分析:

首先,我们分析一下表示时钟时针初始位置的数码j(0≦j≦3)与时刻的对应关系:

0——12点

1——3点

2——6点

3——9点

每移动一次,时针将顺时针旋转90度。

由此我们可以得出:

对于任意一个时钟i(1≦i≦9)来说,从初始位置j出发至少需要Ci=(4-j)mod4次操作,才能使得时针指向12点。

而对每种移动方法要么不采用,要么采用1次、2次或3次,因为操作四次以后,时钟将重复以前状态。

因此,9种旋转方案最多产生49个状态。

移动方案选取与顺序无关。

样例中,最佳移动序列为5849,同样4589序列也可达到目标。

因此,求解过程中可以直接选取序列中从小至大排列的移动序列即可。

设pi表示第i种旋转方法的使用次数(0≦pi≦3,1≦i≦9)。

则可能的解的集合为{P1,P2,……,P9},该集合共含49个状态。

从图2.11中,我们可以分析出9个时钟分别被哪些方法所控制,见下表:

时钟号

控制时钟方案

检验条件

1

1、2、4

C1=(P1+P2+P4)mod4

2

1、2、3、5

C2=(P1+P2+P3+P5)mod4

3

2、3、6

C3=(P2+P3+P6)mod4

4

1、4、5、7

C4=(P1+P4+P5+P7)mod4

5

1、3、5、7、9

C5=(P1+P3+P5+P7+P9)mod4

6

3、5、6、9

C6=(P3+P5+P6+P9)m

od4

7

4、7、8

C7=(P4+P7+P8)mod4

8

5、7、8、9

C8=(P5+P7+P8+P9)mod4

9

6、8、9

C9=(P6+P8+P9)mod4

因此我们可以设计如下枚举算法:

  forp1:

=0to3do

forp2:

=0to3do

.........

forp9:

=0to3do

ifc1满足时钟1andc2满足时钟2and...andc9满足时钟9then

打印解路径;

显然,上述枚举算法枚举了所有49=262144个状态,运算量和运行时间颇大。

我们可以采取缩小可能解范围的局部枚举法,仅枚举第1、2、3种旋转方法可能取的43个状态,根据这三种旋转方法的当前状态值,由下述公式

P4=order(C1-P1-P2);

P5=order(C2-P1-P2-P3);

P6=order(C3-P2-P3);

P7=order(C4-P1-P4-P5);

P8=order(C8-P5-PP9);

P9=order(C6-P3-P5-P6);

其中

得出其余P4……P9的相应状态值。

然后将P1,P2,…,P9代入下述三个检验条件

C5=(P1+P3+P5+P7+P9)mod4

C7=(P4+P7+P8)mod4

C9=(P6+P8+P9)mod4

一一枚举,以求得确切解。

由此可见,上述局部枚举的方法(枚举状态数为43个)比较全部枚举的方法(枚举状态数为49个)来说,由于大幅度削减了枚举量,减少运算次数,因此其时效显著改善,是一种优化了的算法。

程序如下:

programIOI94_4;

const

Inp='input.txt';

Outp='output.txt';

var

Clock,Map:

array[1..3,1..3]ofInteger;

{Clock:

第((I+2)mod3)*3+J个时钟从初始时间到12点的最少移动次数}

{Map:

最短移动序列中,数字((I+2)mod3)*3+J的次数}

procedureInit;

var

I,J:

Integer;

begin

Assign(Input,Inp);Reset(Input);

forI:

=1to3do

{读入9个时钟指针的初始位置,求出每个时钟从初始到12点的最少移动次数}

forJ:

=1to3dobegin

Read(Clock[I,J]);

Clock[I,J]:

=(4-Clock[I,J])mod4;

end;

Close(Input);

end;

functionOrder(K:

Integer):

Integer;

var

c:

Integer;

begin

c:

=k;

whilec<0doinc(c,4);

whilec>4thendec(c,4);

Order:

=k;

end;

procedureMain;{计算和输出最短移动序列}

var

I,J,K:

Integer;

begin

{枚举最短移动序列中数字1、2、3的个数可能取的43种状态}

Assign(Output,Outp);Rewrite(Output);

forMap[1,1]:

=0to3do

forMap[1,2]:

=0to3do

forMap[1,3]:

=0to3dobegin

Map[2,1]:

=Order(Clock[1,1]-Map[1,1]-Map[1,2]);

Map[2,3]:

=Order(Clock[1,3]-Map[1,2]-Map[1,3]);

Map[2,2]:

=Order(Clock[1,2]-Map[1,1]-Map[1,2]-Map[1,3]);

Map[3,1]:

=Order(Clock[2,1]-Map[1,1]-Map[2,1]-Map[2,2]);

Map[3,3]:

=Order(Clock[2,3]-Map[1,3]-Map[2,2]-Map[2,3]);

Map[3,2]:

=Order(Clock[3,2]-Map[3,1]-Map[3,3]-Map[2,2]);

{根据数字1、2、3个数的当前值,得出数字4~9的个数}

if((Map[2,1]+Map[3,1]+Map[3,2])mod4=Clock[3,1])and

((Map[2,3]+Map[3,2

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

当前位置:首页 > 小学教育 > 学科竞赛

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

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