1、穷举法(枚举法),学习目标,理解穷举法的思想方法 学会分析建立正确的穷举步骤,归纳穷举法的穷举技巧 学会优化穷举算法 学会使用穷举法解决现实生活、学习中遇到的问题,用穷举法解决问题,计算机的特点之一就是运算速度快、善于重复做一件事情,“穷举法”正是基于这一特点的最古老的算法。它一般是一时找不到解决问题的更好的途径,即从数学上找不到求解的公式或者规则时,根据问题中的“约束条件”,将解的所有可能情况一一列举出来,然后再逐一验证是否符合整个问题的求解要求,从而得到问题的所有解。,示例1,求满足表达式A+B=C的所有整数解,其中A,B,C为13之间的整数。,解题思路,本题非常简单,即枚举变量A,B,C
2、的所有可能取值情况,对每种取值情况判断是否符合表达式即可。 算法如下for A:=1 to 3 dofor B:=1 to 3 dofor C:=1 to 3 doif(A+B=C) thenwriteln(A, ,B, ,C);,穷举法的定义,所谓穷举法,指的是从可能的解的集合中一一枚举各元素,用题目给定的检验条件判定哪些是无用的,哪些是有用的。能使命题成立的,即为解。,解题思路,示例中的解变量有3个:A,B,C。其中解变量A的可能取值范围A1, 2 ,3解变量B的可能取值范围B1, 2 ,3解变量C的可能取值范围C1, 2 ,3从而问题的可能解有3*3*3=27个,可能解集:(A,B,C)
3、(1,1,1),(1,1,2),(1,1,3),(3,3,1),(3,3,2),(3,3,3)在上述可能解集中,满足题目给定的检验条件(A+B=C)的解元素,即为问题的解。,8,金手指考试网 http:/ 2016年金手指驾驶员考试科目一 科目四 元贝驾考网 http:/ 科目一科目四仿真考试题C1,Grammar,穷举法的使用范围,能确定解变量(枚举变量)的个数 n ; 每个解变量Ai(1 = i = n)的可能值能确定范围且能连续取得。,算法框架,设解变量的个数是n,Ai1解变量Ai的最小值;Aik解变量Ai的最大值(1in),即A11A1A1k,Ai1AiAik,An1AnAnk算法框架
4、如下(伪代码): for A1A11 to A1k do for A2A21 to A2k do for AiAi1 to Aik do for AnAn1 to Ank do if 状态(A1,Ai,An)满足检验条件 then 输出问题的解;,示例2,“水仙花数问题” 。 水仙花数是指一个三位数,它的各位数的立方和,正好是等于该数本身。例如153=13+53+33。请设计算法求解100-999其他的水仙花。,解题思路,该数的百位范围1-9,十位范围0-9,个位范围0-9 约束条件:该数的个、十、百位数的立方和正好是等于该数本身 程序结构选择:三重循环,能优化吗?,解题思路,三位数范围100
5、-999 约束条件:该三位数的各位数的立方和正好是等于该数本身 程序结构选择:一重循环,穷举法,枚举法的特点是算法简单,但有时运算量大。 优化枚举算法(考察重点)枚举算法的时间复杂度=状态总数*考察单个状态的耗时 排除明显不属于解集的元素 减少状态总数(即减少枚举变量和枚举变量的值域) 降低单个状态的考察代价,示例1优化程序,示例算法显然可以修改如下:for A:=1 to 3 dofor B:=1 to 3 dobegin C:=A+B;if(C=1)and(C n2。,示例3,公鸡一只值5元,鸡母一只值3元,小鸡三只值1元。现在有100只鸡,正好值100元钱,问公鸡、母鸡和小鸡各有几只?,
6、设 变量设置为:X表示公鸡只数,Y表示母鸡只数,Z表示小鸡只数。,穷举时如何利用好百鸡和百钱两个已知条件,选择合适的穷举方法,使程序最优化? 变量设置:试找出下列变量的最小穷举范围 X穷举范围: _ Y穷举范围: _ Z穷举范围: _ 优化一下可以考虑 Z的设置方式: _,减少穷举的范围和不必要的穷举是优化穷举算法的关键。,练习,完全数 古希腊人称因子的和等于本身的数是完全数,例如28的因子是1、2、4、7、14,而1+2+4+7+14=28,所以28是一个完全数。编程输出21000内所有的完全数。,破解密码,一张单据上有一个5位数的编号,其百位数和十位数已经变得模糊不清,但是知道这个5位数是
7、37或67的倍数。现在要求设计一个算法,找出所有满足这些条件的5位数,并统计这些5位数的个数。,NO.25*6,n:=25006; For i:=0 to 99 do Beginn:=n+i*100;if (n mod 37=0)or(n mod 67 =0) thenwriteln(n); End;,猜冠军,A,B,C,D,E,F 6人参加跳高决赛,甲乙丙丁4人猜测谁是冠军:甲说:“冠军不是A,就是B。”乙说:“冠军决不是C”丙说:“DEF都不可能是冠军。”丁说:“冠军可能是DEF中的一个”比赛成绩公布时发现,这4个人所说的话中,只有一句话是对的。你能断定谁是冠军吗?,提示:本题关键在问题的
8、转化设定冠军为X(13丙:X=4,For x := 1 To 6 do begins := 0If (x = 1) Or (x = 2) Then s = s + 1;If (x 3 )Then s = s + 1;If (x = 4 )Then s = s + 1;If( s = 1) Then writeln( “冠军是 “, x) End;,输入一根木棒的长度,将该木棒分成三段,每一段的长度为正整数;输出由这三段小木棒组成的不一样边长的三角形的个数。如输入10,则输出2,能组成的两个三角形边长为2、4、4 和3、3、4。,四皇后问题 在4*4的棋盘上安置4个皇后,要求任意两个皇后不在同一
9、行、同一列、同一对角线上,输出所有可能的皇后放置方案。,分析: 1) 本题是一个搜索问题,搜索范围 44,找出符合条件的方案; 2)方案必须满足的条件:任意两个不在同一行、同一列和同一对角线。,const n=4; type stack=array1n of integer; var i1,i2,i3,i4:integer;s:stack; function check:boolean; var i,j:integer; beginfor i:=1 to n-1 dofor j:=i+1 to n do if (si=sj) or (si-i=sj-j) or (si+i=sj+j)then
10、begin check:=false;exitend;check:=true end;,procedure print; var i:integer; beginfor i:=1 to n do write(si:2);writeln end; beginfor i1:=1 to n dofor i2:=1 to n dofor i3:=1 to n dofor i4:=1 to n dobegin s1:=i1;s2:=i2;s3:=i3;s4:=i4;if check then print;end; end.,将19这九个数字填入九个空格中。每一横行的三个数字组成一个三位数。如果要使第二行
11、的三位数是第一行的两倍, 第三行的三位数是第一行的三倍, 应怎样填数。(一共4组解,一组如下图),本题目有9个格子,要求填数,如果不考虑问题给出的条件,共有9!=362880种方案,在这些方案中符合问题条件的即为解。因此可以采用枚举法。但仔细分析问题,显然第一行的数不会超过400,实际上只要确定第一行的数就可以根据条件算出其他两行的数了。这样仅需枚举400次。(优化,program ex_8(input,output);var i,j,k,s:integer;function sum(s:integer):integer;beginsum:=s div 100+s div 10 mod 10+
12、s mod 10end;sumfunction mul(s:integer):longint;beginmul:=(s div 100)*(s div 10 mod 10)*(s mod 10)end;mul,Beginfor i:=1 to 3 dofor j:=1 to 9 doif ji then for k:=1 to 9 doif (kj) and (ki) thenbegin s:=i*100+j*10+k;if 3*s1000 thenif (sum(s)+sum(2*s)+sum(3*s)=45) and (mul(s)*mul(2*s)*mul(3*s)=362880) th
13、enbeginwriteln(s);writeln(2*s);writeln(3*s);writeln;end;end; end.,阿姆斯特朗数。,问题描述:编一个程序找出所有的三位数到七位数中的阿姆斯特朗数。 阿姆斯特朗数也叫水仙花数,它的定义如下:若一个n位自然数的各位数字的n次方之和等于它本身,则称这个自然数为阿姆斯特朗数。例如153(153=1*1*1+3*3*3+5*5*5)是一个三位数的阿姆斯特朗数,8208则是一个四位数的阿姆斯特朗数。,引入,算法描述: for I:=100 to 9999999 dobegin拆分I各位上的数字;计算I的位数;验证是否是阿姆斯特朗数,若是则输出
14、;end;,算法分析: 为了使得程序尽快运行出正确结果,程序中使用了一个数组power存放所有数字的各次幂之值, poweri,j等于i的j次方。变量currentnumber存放当前要被验证的数,数组digit存放当前数的各位数字,开始时digit3=1,其它元素均为0,此时表示当前数为100。 highest为当前数的位数,程序: program ex3(input,outoutp); const maxlen=7; var i,j,currentnumber,highest,sum,total:longint;digit:array 0maxlen+1 of integer;power:
15、array 09,0maxlen of longint; beginfor i:=0 to 9 dobeginpoweri,0:=1; for j:=1 to maxlen do poweri,j:=poweri,j-1*iend;,for i:=1 to maxlen do digiti:=0;digit3:=1; highest:=3; currentnumber:=100; total:=0;while digitmaxlen+1=0 dobeginsum:=0;for i:=1 to highest do sum:=sum+powerdigiti,highest;if sum=currentnumberthen begin total:=total+1;write(currentnumber:maxlen+5);if total mod 6=0 then writeln end;,digit1:=digit1+1; i:=1;while digiti=10 dobegindigiti+1:=digiti+1+1; digiti:=0; i:=i+1 end;if ihighest then highest:=i;currentnumber:=currentnumber+1end;writeln end.,