1穷举法
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
竞赛辅导1------穷举法
一、穷举法
基本思想:
是根据提出的问题穷举所有可能的状态,并用问题给定的条件寻找问题的解。
适用穷举的的问题需要满足下面两个条件:
1) 可预先确定状态(搜索元/变量)的元素个数
2)状态元素的可能值为一个连续的值域
穷举算法的模式:
1)搜寻问题解的可能范围:用循环或循环嵌套结构实现
2)确定约束条件:
3)程序的优化,以减少搜索范围和程序运行时间
穷举算法的优点:
1)由于穷举算法一般是现实生活问题的直译,因此比较直观,易于理解
2)由于穷举算法建立在考察大量状态、甚至是穷举所有状态的基础上,所以算法正确性比较容易证明。
穷举算法的缺点:由于穷举的数据量过大,效率较低。
二、实例解析:穷举算法的一般设计过程先对问题进行直译,然后优化。
(一)、问题的“直译”:
将自然语言描述的过程直接“翻译”成程序语言的实现过程(算法),找到搜索元,找到搜索元的数据范围和问题的约束条件。
例1、百鸡百钱问题:公鸡一只5文钱,母鸡一只3文钱,小鸡3只2文钱。
要求一百文钱买一百只鸡,编程计算各种鸡的具体数量。
分析:设三种鸡的数量为x,y,z ,则原问题可转化为在1=<x<100,1=<y<100,1=<z<100,范围内搜寻满足约束条件5*x + 3*y+z/3=100的x,y,z的值。
则,原问题可直接转化成的穷举算法如下:
for x---1 to 100 do
for y---1 to 100 do
begin
z=100-x-y;
if 5*x + 3*y+z/3=100 then 输出x,y,z;
end;{for}
能直译的问题的一半的特点是:
1)输出变量的个数确定,数据在可选范围内连续或者满足一定的递增(递减)关系
2)约束条件直观,可以用解析式表达或者近似表达
3)直译穷举算法时间复杂度为一个多项式。
4)数据范围较大时不适宜采用直译方法,时间耗费较大。
练习:
1、求完全数:古希腊人认为因子的和等于它本身的数是一个完全数(自身因子除外),例如28的因子是1、
2、4、7、14,且1+2+4+7+14=28,则28是一个完全数,编写一个程序求2-1000内的所有完全数。
6、28、496(或者求100—999中的水仙花数,即三位数abc,若abc=a^3 + b^3 + c^3 ,则称abc为水仙花数。
如153,1^3 + 5^3 +3^3 =153 ,则153是水仙花数。
15
3、370、371、407)
2、找出四位整数abcd中满足下述关系的数(注意取高两位和低两位):2025、3025、9801
(ab+cd)(ab+cd)=abcd
3、求两个自然数m,n的最小公倍数(搜索方法)。
4、从n个数中挑选出最大的数(搜索方法)。
5、四个学生上地理课时,回答我国四大淡水湖大小时说这样的话。
甲说:“最大洞庭湖,最小洪泽湖,鄱阳湖第三“;乙说:“最大洪泽湖,最小洞庭湖,鄱阳湖第二,太湖第三“;丙说:“最小洪泽湖,洞庭湖第三“;丁说:“最大鄱阳湖,最小太湖,洪泽湖第二,洞庭湖第三“。
其中每个学生仅答对一个,请编程确定湖的大小。
(看懂程序,掌握约束条件的实现技巧,ord()的使用) 2 4 1 3 参考程序:
program p5;
var dong ,hong,bo ,tai:integer;
begin
for dong :=1 to 4 do
for hong:=1 to 4 do
if hong<>dong then
for bo:=1 to 4 do
if (hong<.bo) and (bo<>dong) then
begin
tai:=10-dong-hong –bo;
if(ord(dong=1)+ord(hong=4)+ord(bo=3)=1) and (ord(hong=1)+ord(dong=4)+ord(bo=2)+ord(tai=3)=1) and (ord(dong=3)+ord(hong=4)=1)and(ord(bo=1)+ord(tai=4)+ord(hong=2)+ord(dong=3)=1)
then
writeln(‘dong:’,dong,’hong:’,hong,’bo:’,bo,’tai:’,tai);
end;
readln
end.
6、跳远
1-1所示:
一个小孩想站在某个三角形I的顶端,跳到三角形j的顶端上(i<j).他总是朝着斜向45度的方向起跳,且初始水平速度v不超过给定值v0.在跳跃过程中,由于受到重力作用(不计空气阻力),小孩将沿着抛物线行进,水平运动方程x=x0+v*t ,竖直运动方程为y=y0+v*t-0.5g*t ,运动轨迹时个上凸的抛物线。
去g=10.0 ,(x0,y0)是起跳坐标。
编程求出他从没个位置起跳能达到的最远三角形的编号。
注意:跳跃过程中不能碰到非起点和终点的其他三角形。
输入:第一行为两个数n,vo(3=<n=<10,1=<v0=<100),表示三角形的个数和最大水平速度。
第二行又n个正整数li(1=<li=<20),表示从做到右各个三角形的边长。
输出:输出一行,包含n-1个数,表示从三角形1,2,3,….,-1的定点能到达的最右三角形的编号。
如果从某三角形出发无法达到任何三角形,相应的数为0。
(二)、穷举算法的优化:
1、一根29cm长的尺子,只允许在上面刻7个刻度,要能用他俩出1—29cm的各种长度。
试问这根
尺子的刻度应该怎样选择。
问题分析:
直译:能够得到的信息
(1)选择7个刻度的所有可能情况:
C[29,7]=(29*28*…*24*23)/(1*2*…*6*7)=1560780
(2) 对于每一组刻度的选择需要判断是否能将1—29cm的各种刻度都能量出来。
例如设选择的刻度位a1,a2,a3,a4,a5,a6,a7,则可以度量出的刻度为:
a1,29-a1;
a2,a2-a1,29-a2;
a3,a3-a1,a3-a2,29-a2;
……
a7,a7-a1,a7-a2,a7-a3,a7-a4,a7-a5,a7-a6,29-a7;
共有2+3+4+…+8=32种刻度,其中存在重复值,不一定能度量出1—29种的所有刻度。
例如,设a1,a2,a3,a4,a5,a6,a7,(1=<a1=<29,….1=<a7=<29)分别为1,3,6,10,15,21,28,具体能量出的刻度值(略)。
(3)如果有了刻度a1,a2,a3,a4,a5,a6,a7,那么根据对称性29-a1, 29-a2, 29-a3, 29-a4, 29-a5, 29-a6, 29-a7也能量出来。
优化:
1)想量出1—29到所有刻度,其中1或28必须能够两处,因此刻度中必然有1或28,则本题只需在2—27中选择六个刻度即可。
可能数目为:
C[26,6]=(26*25*..*22*21)/(1*2*..*5*6)=230230
搜索范围减少。
2)7个刻度必然两两不等,有大小之分,因此,可设a1(=1)<a2<a3<a4<a5<a6<a7<29,搜索状态数减少。
程序实现:判定7个刻度是否能够度量1—29的所有长度,可以用集合方法,也可以用数组的0,1数据判断。
下面使用数组实现:1 2 14 18 21 24 27;1 4 10 16 22 24 27
program kedu;
const n=29;m=1;
var a:array[1..7] of integer;
b:array[1..n] of 0..1;
f:boolean;
I,j:integer;
Begin
A[1]:=1;
For a[2]:=2 to n-7 do
For a[3]:=a[2]+1 to n-6 do
For a[4]:=a[3]+1 to n-5 do
For a[5]:= a[4]+1 to n-4 do
For a[6]:= a[5]+1 to n-3 do
For a[7]:= a[6]+1 to n-2 do
Begin
For i:=1 to 29 do b[I]:=0;
For I:=1 to 7 do
Begin
B[a[I]]:=1;b[n-a[I]]=1;b[n]:=1;
For j:=I+1 to 7 do b[abs(a[j]-a[I])]:=1
End;
J:=0;
For I:=1 to do j:=j+b[I];//这个技巧记住
If j=n then begin
For I:=1 to 7 do write(a[I]:4);
Writeln;
End;
End;
End.
2、邮局发行一套票面有四种不同值的邮票,如果每封信所贴邮票张树不超过三枚,存在整数r,使得用不超过三枚的邮票,可以贴出连续的整数1、2、
3、….、r来,找出这四种面值数,使得r值最大。
问题分析:本题的算法与上题有相同之处,上题是知道总长,搜索7个刻度位置,而本题则是知道每封信邮票数的范围(<=3),邮票有四种类型,编程找出能使面值最大邮票。
1 4 7 8——24
程序实现:
program youpiao;
var a,b,c,d:integer;
x,x0,x1,x2,x3,x4:integer;
st1:set of 1..100;
function numb(a,b,c,d:integer):integer;
var n1,n2,n3,n4,sum:integer;
begin
st1:=[];
for n1:=0 to 3 do
for n2:=0 to 3-n1 do
for n3:=0 to 3-n1-n2 do
for n4:=0 to 3-n1-n2-n3 do
begin
if n1+n2+n3+n4<=3 then
begin
sum:=n1*a+n2*b+n3*c+n4*d ; {计算新芬的邮票面值}
st1:=st1+[sum] {利用集合判断}
end;
end;
sum:=1;
while sum in st1 do
sum:=sum+1;
numb:=sum-1;
end;{函数结束}
begin{main}
a:=1; x0:=0;
for b:=a+1 to 3*a+1 do
for c:=b+1 to 3*b+1 do {每种邮票的可能取值的范围}
for d:=c+1 to 3*c+1 do
begin
x:=numb(a,b,c,d);{调用函数求每封信的邮票面值}
if x>x0 then
begin
x0:=x;x1:=a;x2:=b;x3:=c;x4:=d {保存最大面值邮票}
write(x1:5,x2:5,x3:5,x4:5);
writeln(‘’:10,’x0=’,x0);
end;
end;
end.
3、*编一个程序,对给定的自然数n,找出满足下述关系的最小s:
s=p^n +q^n = r^n + t^n
其中p,q,r,t为自然数,且p,q和r,t不全相同。
有解时输出解,否则给出无解信息。
问题的分析:
1)单纯用穷举法则对给定的n,使p,q,r,t在[0,trunc(exp(ln(maxint)/n))]中,穷尽其值,对每次p,q,r,t的一个组合,验证p^n +q^n = r^n + t^n,且p<>q,p<>t,p<>r,q<>r,q<>t,r<.>t,对满足以上条件的p,q,r,t
选出,并找出其中最小的。
2)这样搜索时间太长,适当改变表达式和存储方式,用p^n-r^n=t^n-q^n的方法和用二维数组存放差的结果,行、列下标分别表示p,q,r,t的值.设n=3,则列表a^3-b^3如下:
通过上表可以看出:tab[1,10]=tab[9,12]=999,找到一组p,q,r,t,s=999与前面的s值进行比较,记下最小的s的值。
{通过查数据列表,减少搜索时间,程序优化}
3)用数组存放此表,只需存储上三角矩阵。
三角矩阵的数据特点是:设cn=c^n则tab[c,c+1]=(c+1)^n-c^n,而tab[j,c+1]=∑tab[k,k+1](j=1..c,k=j..c),对新产生的一列tab[j,c+1]减产三角矩阵中是否有相同的数,若有便退
出循环,输出满足条件的p,q,r,t的值。
例如:tab[1,4]=tab[1,
2]+tab[2,3]+tab[3,4]=63,tab[2,5]=tab[2,3]+tab[3,4]+tab[4,5]=117
程序实现:用d数组存放上三角矩阵的值。
Program ppp;
Var n,pq,r,t,s,c,cn,cln,I,k,dc1,dc2,iln,j,jln,x:integer;
S,cn,cln,iln,jln:longint;
D:array[1..100] of longint;
Begin
Writeln(‘input number n:’);
Readln(n);
S:=maxint;
Cn:=1;
For c:=1 o trunc(exp(ln(s)/n)) do
Begin
Cln:=1;
For I:=1 to n do
Cln:=cln*(c+1);
D[c]:=cln-cn;
Cn:=cln;
Dc1:=0;
I:=0;
Repeat;
Dc1:=dc1+d[ I ] ;
J:=c-1;
Repeat
K:=j;
Dc2:=0;
While (dc2<dc1) and (k>=1) do
Begin
Dc2:=dc2+d[k];
K:=k-1;
End;
If dc2=dc1 then
Begin
Iln:=1; jln:=1;
For x:=1 to n do
Begin
Iln:=iln*I;
Jln:=jln*(j+1);
While(‘s=’,iln+jln:x,’p=’,c+1:x,’q=’,k+1:x,’r=’,I:x,’t=’,j+1:x);
If iln_jln<s then
Begin
S:=iln+jln;
P:=c+1;
Q:=k;
R:=I;
T:=j+1;
End;{if}
K:=0;
END;{ IF }
J:=j-1;
Until (k=0) or (j=0);
I:=I-1;
Until i=0;
End;
If s=maxint then writeln(‘ It cannot be solved’);
End.
练习:立方体问题:
现有一个棱长为n的;立方体,可以分成n^3个1*1*1的单位立方体。
每个单位立方体都有一个整数值。
N^3各单位立方体的数和不会超过longint范围。
现在要求在这个立方体中找到一个完整单位立方体的长方体,使得该长立方体内所有单位立方体的数和最大。
输入:
n(1=<n=<20)
n个n*n的数字矩阵,每个数字矩阵代表一层,每个数字代表一个单位立方体的整数值,-999=<单位立方体的整数值=<999
输出:长方体的数和。