简单枚举算法教案
var len : array[1 .. 20] of longint; x, y : array[1 .. 20] of double;{三角形顶端顶点的坐标序列} l, h, t, v, v0 : double; ok : boolean;{跳跃成功标志} i, j, k, n, best : integer; begin read(n, v0);{输入三角形的个数和最大水平初速度} for i ← 1 to n do read(len[i]);入从左到右各个三角形的边长} x[1] ← len[1] / 2;{计算每一个三角形顶端顶点的坐标} y[1] ← len[1] * sqrt(3) / 2; for i ← 2 to n do begin x[i] ← x[i - 1] + len[i - 1] / 2 + len[i] / 2; y[i] ← len[i] * sqrt(3) / 2; end;{for}
for i ← 1 to n - 1 do{依次计算每一个三角形所能到达的最远点} begin best ← 0;{从三角形i出发能到达的最右的三角形编号初始化} for j ← i + 1 to n do{依次枚举右方的每一个三角形} begin l← x[j] - x[i];{计算三角形i与三角形j的两个顶端顶点的水平距离和垂直 距离} h ← y[j] - y[i]; if l < h then break;{若起跳角度超过45度,则无法从三角形i起跳} v ← sqrt(5 * l * l / (l - h));{计算即时速度v} if v > v0 then break;{若大于极限速度v0,则无法从三角形i起跳} ok ← true; for k ← i + 1 to j - 1 do{判断跳跃过程中是否碰到其他三角形} begin t ← (x[k] - x[i]) / v;{计算到达三角形k的时间}
简单枚举算法教案
朱全民
ห้องสมุดไป่ตู้
简单枚举法
枚举法 所谓枚举法,指的是从可能的解集合中一一枚举各元素,用 题目给定的检验条件判定哪些是无用的,哪些是有用的.能 使命题成立,即为其解。一般思路: 对命题建立正确的数学模型; 根据命题确定的数学模型中各变量的变化范围(即可能解 的范围); 利用循环语句、条件判断语句逐步求解或证明; 枚举法的特点是算法简单,但有时运算量大。对于可能确 定解的值域又一时找不到其他更好的算法时可以采用枚举 法。
虽然枚举法本质上属于搜索策略,但是它与回溯法有所不同。 虽然枚举法本质上属于搜索策略,但是它与回溯法有所不同。因为适用枚 举法求解的问题必须满足两个条件: 举法求解的问题必须满足两个条件: 可预先确定每个状态的元素个数n; ⑴可预先确定每个状态的元素个数 ; ⑵状态元素a1,a2,…,an的可能值为一个连续的值域。 状态元素 , 的可能值为一个连续的值域。 设 ai1— 状 态 元 素 ai 的 最 小 值 ; aik— 状 态 元 素 ai 的 最 大 值 (1≤i≤n) , 即 a11≤a1≤a1k,a21≤a2≤a2k, ai1≤ai≤aik,……,an1≤an≤ank , for a1←a11 to a1k do fo a2←a21 to a2k do for ai←ai1 to aik do for an←an1 to ank do if 状态 1,…,ai,…,an)满足检验条件 状态(a , , 满足检验条件 then 输出问题的解; 输出问题的解; …………………… ……………………
分析: 分析 根据已知条件, 因此排除了一种可能性, 根据已知条件,A<>1,B<>2,C<>3,D<>4,E<>5,因此排除了一种可能性,只 因此排除了一种可能性 种情况了。 有4!=24种情况了。 ! 种情况了
Program Exam; Var A,B,C,D,E :Integer; Cr :Array[1..5] Of Char; Begin For A:=1 To 5 Do For B:=1 To 5 Do For C:=1 To 5 Do For D:=1 To 5 Do For E:=1 To 5 Do Begin If (A=1) Or (B=2) Or (C=3) Or (D=4) Or (E=5) Then Continue; {ABCDE没猜对一个人的名次 没猜对一个人的名次} 没猜对一个人的名次 If [A,B,C,D,E]<>[1,2,3,4,5] Then Continue;{他们名次互不重复 他们名次互不重复} 他们名次互不重复 If Ord(A=2)+Ord(B=5)+Ord(C=4)+Ord(D=1)+Ord(E=3)<>2 Then Continue; {DAECB猜对了两个人的名次 猜对了两个人的名次} 猜对了两个人的名次 If (B=A+1) Or (C=B+1) Or (D=C+1) Or (E=D+1) Then Continue; {ABCDE没猜对一对相邻名次 没猜对一对相邻名次} 没猜对一对相邻名次 If Ord(A=D+1)+Ord(E=A+1)+Ord(C=E+1)+Ord(B=C+1)<>2 Then Continue; {DAECB猜对了两对相邻人名次 猜对了两对相邻人名次} 猜对了两对相邻人名次 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.
逻辑判断问题
在某次数学竞赛中, 、 、 、 、 五名学生被取为前五名 五名学生被取为前五名。 在某次数学竞赛中 A、B、C、D、E五名学生被取为前五名。请据下 列说法判断出他们的具体名次, 即谁是第几名? 列说法判断出他们的具体名次 即谁是第几名? 条件1: 你如果认为A, 条件 你如果认为 B, C, D, E 就是这些人的第一至第五名的名次排 便大错。因为: 列, 便大错。因为 没猜对任何一个优胜者的名次。 没猜对任何一个优胜者的名次。 也没猜对任何一对名次相邻的学生。 也没猜对任何一对名次相邻的学生。 条件2: 你如果按D, 来排列五人名次的话, 其结果是: 条件 你如果按 A , E , C , B 来排列五人名次的话 其结果是 说对了其中两个人的名次。 说对了其中两个人的名次。 还猜中了两对名次相邻的学生的名次顺序。 还猜中了两对名次相邻的学生的名次顺序。 分析:本题是一个逻辑判断题, 分析:本题是一个逻辑判断题,一般的逻辑判断题都采用枚举法进行 解决。 个人的名次分别可以有 个人的名次分别可以有5! 种排列可能, 比较小, 解决。5个人的名次分别可以有 !=120种排列可能,因为 种排列可能 因为120比较小, 比较小 因此我们对每种情况进行枚举, 因此我们对每种情况进行枚举,然后根据条件判断哪些符合问题的要 求。
巧妙填数
将1~9这九个数字填入九个空格中。每一横行的 三个数字组成一个三位数。如果要使第二行的三 位数是第一行的两倍, 第三行的三位数是第一行 的三倍, 应怎样填数。如图
1 3 5 9 8 7 2 4 6
分析
本题目有9个格子,要求填数,如果不考虑问题给出的条件,共有9! =362880种方案,在这些方案中符合问题条件的即为解。因此可以采 用枚举法。 但仔细分析问题,显然第一行的数不会超过400,实际上只要确定第 一行的数就可以根据条件算出其他两行的数了。这样仅需枚举400次。 因此设计参考程序:
var i,j,k,s:integer; function sum(s:integer):integer; begin sum:=s div 100 + s div 10 mod 10 + s mod 10 end; function mul(s:integer):longint; begin mul:=(s div 100) * (s div 10 mod 10) * (s mod 10) end;
枚举法优缺点
枚举法的优点: 枚举法的优点: ⑴由于枚举算法一般是现实生活中问题的“直译”,因此比较直观,易于 理解; ⑵由于枚举算法建立在考察大量状态、甚至是穷举所有状态的基础上,所 以算法的正确性比较容易证明。 枚举法的缺点: 枚举法的缺点 枚举算法的效率取决于枚举状态的数量以及单个状态枚举的代价,因此 效率比较低。
跳远
在水平面上整齐的放着n个正三角形,相邻两个三角形的底边之间无空隙, 如左图所示。一个小孩子想站在某个三角形i的顶端,跳到三角形j的顶端上(i<j)。 他总是朝着斜向45度的方向起跳,且初始水平速度v不超过一个给定值v0。在跳跃过 程中,由于受到重力作用(忽略空气阻力),小孩子将沿着抛物线行进,水平运动方 程为x = x0 + vt,竖直运动方程为y = y0 + vt – 0.5gt2,运动轨迹是一条上凸的抛 物线。取g=10.0,(x0, y0)是起跳点坐标。 请编程求出他从每个位置起跳能到达的最远三角形的编号。注意:跳跃过程中不许碰 到非起点和终点的其他三角形。
如何判断顶点k是否在抛物线下呢?我们可以算出到达时间t0 = dx / v(其 中dx为起点到顶点k的水平坐标增量),然后算出该时刻的竖直坐标增量 vt0 – 0.5t02。如果此增量大于起点到顶点k的竖直坐标增量,则抛物线在 上方。只有起点和终点之间任何一个三角形的顶点不在抛物线下方,则跳 远不能完成。 我们在枚举过程中不断将小孩所能跳到的点j调整为best。 枚举结束后, best即为试题要求的最远点。
示例
求满足表达式A+B=C的所有整数解,其中A,B,C为1~100之间的整数。 分析:本题非常简单,即枚举所有情况,符合表达式即可。 算法如下: for A := 1 to 100 do for B := 1 to 100 do for C := 1 to 100 do if A + B = C then Writeln(A, ‘+’, B, ‘=’, C); 显然可以修改如下: for A := 1 to 100 do for B := 1 to 100 do C := A+B if (C<=100) AND (C>=1)then Writeln(A, ‘+’, B, ‘=’, C);