收藏 分享(赏)

第2讲 穷举.doc

上传人:gnk289057 文档编号:9456250 上传时间:2019-08-08 格式:DOC 页数:36 大小:279KB
下载 相关 举报
第2讲  穷举.doc_第1页
第1页 / 共36页
第2讲  穷举.doc_第2页
第2页 / 共36页
第2讲  穷举.doc_第3页
第3页 / 共36页
第2讲  穷举.doc_第4页
第4页 / 共36页
第2讲  穷举.doc_第5页
第5页 / 共36页
点击查看更多>>
资源描述

1、1程序设计竞赛系列讲座杨克昌第 1 讲 程序设计竞赛引论第 2 讲 穷举第 3 讲 递推第 4 讲 递归第 5 讲 回溯第 6 讲 动态规划第 7 讲 综合训练2第 2 讲 穷举穷举是计算机程序设计引导入门的基础算法,也是在数量较小的问题求解中应用广泛的算法。应用穷举设计可以非常简明地解决许多实际问题。本章介绍统计求和、解方程、解不等式、求最值以及涉及素数的基础案例的穷举求解,并由整币兑零、完美综合式与和积三角形三个安全的求解说明穷举设计的改进与优化。2.1 穷举概述1. 穷举的概念穷举法又称列举法、枚举法,是蛮力策略的具体体现,是一种简单而直接地解决问题的方法。其基本思想是逐一列举问题所涉及

2、的所有情形,并根据问题提出的条件检验哪些是问题的解,哪些应予排除。通常程序设计入门都是从穷举设计开始的。今天,计算机的运算速度非常快,应用穷举设计程序可快捷地解决一般数量的许多实际应用问题。穷 举 法 的 特 点 是 算 法 设 计 比 较 简 单 , 解 的 可 能 为 有 限 种 , 一 一 列 举 问 题 所 涉 及 的 所 有情 形 。穷举法常用于解决“是否存在”或“有多少种可能”等问题。其中许多实际应用问题靠人工推算求解是不可想象的,而应用计算机来求解,充分发挥计算机运算速度快、擅长重复操作的特点,穷举判断,快速简便。应用穷举时应注意对问题所涉及的有限种情形须一一列举,既不能重复,又

3、不能遗漏。重复列举直接引发增解,影响解的准确性;而列举的遗漏可能导致问题解的遗漏。2. 穷举的框架描述穷举通常应用循环结构来实现。在循环体中,根据所求解的具体条件,应用选择结构实施判断筛选,求得所要求的解。穷举法的框架描述:n=0;for(k=;k;k+) / 根据指定范围实施穷举 if() / 根据约束条件实施筛选 printf(); / 输出满足要求的解 n+; / 统计解的个数 有些问题没有明确的区间限制,可根据问题的具体实际试探性的从某个数开始,增值穷举,对每一个数作一判断,若满足条件即输出结果,结束穷举。尽管穷举比较简单,在应用穷举设计求解实际问题时要认真分析,准确选定穷举范3围与约

4、束条件。3. 穷举的实施步骤应用穷举设计求解,通常分以下几个步骤:(1)根据问题的具体情况确定穷举量(简单变量或数组) ;(2)根据确定的范围设置穷举循环;(3)根据问题的具体要求确定筛选约束条件;(4)设计穷举程序并运行、调试,对运行结果进行分析与讨论。当问题所涉及数量非常大时,穷举的工作量也就相应较大,程序运行时间也就相应较长。为此,应用穷举求解时,应根据问题的具体情况分析归纳,寻找简化规律,精简穷举循环,优化穷举策略。4. 穷举设计的意义虽然巧妙和高效的算法很少来自穷举,但穷举设计作为一种常用的基础算法不能受到冷漠与轻视:(1) 理论上,穷举可以解决可计算领域中的各种问题。尤其处在计算机

5、计算速度非常高的今天,穷举的应用领域是非常广阔的。(2) 在实际应用中,通常要解决的问题规模不大,用穷举设计的算法其运算速度是可以接受的。此时,设计一个更高效率的算法代价不值得。(3) 穷举可作为某类问题时间性能的底限,用来衡量同样问题的更高效率的算法。本章将通过若干典型案例的求解,说明穷举的实际应用。2.2 统计与求和统计与求和是程序设计最基本的课题,通常只要合理运用穷举即可简捷地解决问题。本节介绍最简真分数与数字有特殊要求的整数这两个典型案例的穷举求解,提高对运用穷举实施统计与求和技巧的认识。2.2.1 最简真分数统计求和 1. 案例提出统计分母在指定区间a,b的最简真分数(分子小于分母,

6、且分子分母无公因数)共有多少个,并求这些最简真分数的和(正整数 a,b 从键盘输入)。2算法设计设分数为分子为 i,分母为 j,最简真分数的和为 s。在指定范围内a,b穷举分数的分母 j:ab;同时对每一个分母 j 穷举分子 i:1j-1。4对每一分数 i/j,置 t=0,然后进行是否存在公因数的检测。如果分子 i 与分母 j存在大于 1 的公因数 u,说明 i/j 非最简真分数,应予舍略。因为分子分母同时约去 u 后,分母可能不在a,b,即使在a,b时前面已作了统计求和。注意到公因数 u 的取值范围为2,i,因而设置 u 循环在2,i中穷举 u,若满足条件j%u=0 double s;pri

7、ntf(“ 最简真分数分母在a,b内,请确定 a,b: “);scanf(“%d,%d“, / 输入区间的上下限 n=0;s=0;for(j=a;j2)是从键盘输入的一位正整数。首先,通过循环 n-1 次相乘求出最小的 n 位整数 t。然后通过 k 从 t 至 10*t-1 循环,穷举所有 n 位整数。为了检测 k 是否含有数字 m,是否恰含 2 个数字 m,每个 n 位整数 k 赋给 d(为了保持k 不变)。然后通过 n 次求余先后分离出 k 的数字 c,并用 f(c)=f(c)+1 统计数字 c 的个数。例如 f(7)=2,说明整数 k 中恰含 2 个数字 7;若 f(3)0,说明整数 k

8、 中含有数字 3.然后据 f(m)0 long d,k,g1,g2,s1,s2,t; printf(“ 请输入一位整数 m,n: “);scanf(“%d,%d“,t=1;for(k=1;k0 s1+=k;if(fm=2 s2+=k; printf(“ 含数字%d 且不能被%d 整除的%d 位整数的个数 g1=%ld n“,m,m,n,g1);printf(“ 这些整数的和为 s1=%ld n“,s1);printf(“ 恰含 2 个数字%d 且不能被%d 整除的%d 位整数个数 g2=%ld n“,m,m,n,g2);printf(“ 这些整数的和为 s2=%ld n“,s2);4. 程序运

9、行示例请输入一位整数 m,n: 7,5含数字 7 且不能被 7 整除的 5 位整数的个数 g1=32152这些整数的和为 s1=1894711910恰含 2 个数字 7 且不能被 7 整除的 5 位整数个数 g2=5837这些整数的和为 s2=3680027942.3 解方程解方程(组) 是程序设计的应用课题之一。有些较为复杂的方程用常规方法是难以胜任的,运用程序设计可望有效求解,得到相应的准确解或近似解。2.3.1 韩信点兵1. 案例提出在中国数学史上,广泛流传着一个“韩信点兵”的故事。韩信是汉高祖刘邦手下的大将,他英勇善战,智谋超群,为汉朝建立了卓绝的功劳。据说韩信的数学水平也非常高超,他

10、在点兵的时候,为了知道有多少个兵,同时又能保住军事机密,便让士兵排队报数:按从 1 至 5 报数,记下最末一个士兵报的数为 1;再按从 1 至 6 报数,记下最末一个士兵报的数为 5;再按 1 至 7 报数,记下最末一个报的数为 4;最后按 1 至 11 报数,最末一个士兵报的数为 10。你知道韩信至少有多少兵?72. 求解要点设兵数为 x,则 x 满足下述的不定方程组:x=5y+1 即 x=1 (mod 5)x=6z+5 x=5 (mod 6)x=7u+4 x=4 (mod 7)x=11v+10 x=10 (mod 11)其中 y,z,u,v 都为正整数。试求满足以上方程组的最小正整数 x。

11、应用穷举可得到至少的兵数。x 从 1 开始递增 1 取值穷举当然可以,但不必要。事实上穷举次数可联系问题的具体实际大大缩减。(1) 注意到 x 除 11 余 10,于是可设置 x 从 21 开始,以步长 11 递增。此时,只要判别前三个条件即可。(2) 由以上第 2,4 两方程知 x+1 为 11 的倍数,也为 6 的倍数。而 11 与 6 互素,因而 x+1 必为 66 的倍数。于是取 x=65 开始,以步长 66 递增。此时,只要判别 x%5=1 与x%7=4 两个条件即可。这样可算得满足条件的最小整数 x 即点兵的数量。 3. 程序实现/ 韩信点兵 #include void main(

12、) long int x;x=65;while(1) x=x+66;if(x%5=1 break;运行程序,得至少有兵:2111 个。4. 案例一般化上述点兵是报 4 遍数,一般化为报 n 遍数,第 i 次从 1 至 p(i)报数时,最末一名士兵报数为 r(i), (i=1,2,.,n) 。这里,n 与 p(i),r(i)(i=1,2,.,n)均从键盘输入。(1) 设计要点设置输入循环,输入中如果出现 r(i)=p(i),这在报数过程中是可能的。为统一处理,这里需归零 r(i)=0。8设人数为 x,并取初值 x=r(n),进入永真循环。循环中 x 按步长 p(i)增值,即 x=x+p(n)。对

13、每一次 x 取值,置标志 t=0。然后在 i循环中进行 n-1 次检测:若对某一 i,x%pi!=ri,即人数 x 不满足第 i 次报数,t=1,x 需增值再试;若对所有 i, (i=1,2,.,n) ,x%pi=ri,即此时人数 x 满足所有 n 次报数,保持原有 t=0,则输出人数 x 为所求,结束。(2) 程序设计/ 一般化韩信点兵 #include void main() long n,t,i,x,p20,r20;printf(“ 按 1 至 p 报数,最末一人报数为 r。n“);printf(“ 需报数 n 轮, 请输入 n: “ );scanf(“%ld“,for(i=1;i#in

14、cludedouble fny(double x) / 自定义函数 fny,用来定义方程式 return 2*pow(x,9)*sin(x)+3*pow(x,4)-5*exp(x)-4; / 据方程实际改变 void main() int k,t;double a,b,c,x,x1,y,mi;10printf(“ 求方程在a,b中的一个解,请确定 a,b: “);scanf(“%lf,%lf“,for(t=0,x=a;x#include11double fny(double x) / 自定义函数 fny,用来定义方程式 return 2*pow(x,9)*sin(x)+3*pow(x,4)-5

15、*exp(x)-4; / 可根据方程实际改变 void main() int i,t=0;double a,b,x,x1,x2,c;printf(“ 求方程在a,b中的一个解,请确定 a,b: “);scanf(“%lf,%lf“,for(x=a;x0) / 如果变为同号,缩小循环范围 x2=x;x1=x-c;break; / 调整循环的初值 x1 与终值 x2 c=c/10; / 缩小循环步长求精 x=(x1+x2)/2;printf(“ 所求方程的一个解为 x=%f“,x); / 输出解,小数点后 6 位 4. 程序运行结果求方程在a,b中的一个解,请确定 a,b: 1,3所求方程的一个解

16、为 x=1.2498802.4 解不等式 应用程序设计求解一些难度较大的不等式是程序设计应用的一个有趣的课题。解不等式通常只要简单穷举即可实现。2.4.1 分数和不等式1. 案例提出试解下列关于正整数 n 的分数不等式12(1)20143210n2. 设计要点为一般计,解不等式(2)214321mnm这里正整数 m1,m2 从键盘输入(m1m1 退出循环,赋值c=i,所得 c 为 n 解区间的下限。继续在 sm2 退出循环,通过赋值 d=i-1,所得d 为 n 解区间的上限。注意,解的上限是 d=i-1,而不是 i。然后打印输出不等式的解区间c,d。3. 程序实现/ 解分数不等式 #inclu

17、de #includevoid main() long c,d,i,m1,m2; double s;printf(“ 请输入正整数 m1,m2(m1void main() long d,n,k; double s;printf(“n 请输入正整数 d: “);scanf(“%d“,printf(“ %dd) break;n=n+3;printf(“n n=%ld“,n); / 得一个区间解 k=1;s=0;while(k0) s=s+1.0/k;else s=s-1.0/k;14if(sd) / 得一个离散解 printf(“n n=%ld“,k);k+;(3) 程序运行示例请输入正整数 d:

18、 55=203938n=203936注意:前一个是区间解,后一个是离散解。要特别注意,不要把后一个解遗失。2.5 求最值求最值通常是程序设计最具魅力的课题之一。本节介绍两个有趣的最值案例求解,是运用穷举求解的典型手法。2.5.1 基于素数的代数和1. 案例提出定义和:121397531)( nns (和式中第 k 项(2k-1)/(2k+1)的符号识别:分子分母中有且只有一个素数,取“+” ;分子分母中没有素数或两个都是素数时取“-” 。)1) 求 s(2011)(精确到小数点后 5 位)。2) 设 1#includevoid main() int t,j,n,k,k1,k2,a3000;do

19、uble s,s2,smax,mi;printf(“ 请输入整数 n: “); scanf(“%d“, for(k=1;ksmax)smax=s;k1=k; / 比较求最大值 smax if(fabs(s)#include void main() double a,s,a1,s1,b,k,t,x,y,max=0;printf(“ 求区间x,y中整数的因数比最大值.“);printf(“ 请输入整数 x,y:“);scanf(“%lf,%lf“,for(a=x;a18#include void main()long a,b,k; int s,x;a=1;while (1) a+;s=0; / 检

20、验 a 世纪 for(b=a*100-99;bn,则区间f+1,f+n中的 n 个数为最小的连续 n 个合数。应用试商法求指定区间c,d(约定起始数 c=3,d=c+10000)上的所有素数。求出该区间内的一个素数 m,设前一个素数为 f,判别:若 m-fn,则输出结果f+1,f+n后结束;否则,作赋值 f=m,为求下一个素数作准备。如果在区间c,d中没有满足条件的解,则作赋值:c=d+2,d=c+10000,继续试商下去,直到找出所要求的解。3. 程序实现/ 求最小的连续 n 个合数 #include #include void main() long c,d,f,m,j; int t,n;

21、printf(“ 求最小的 n 个连续合数.n“);printf(“ 请输入 n:“); scanf(“%d“,c=3;d=c+10000;f=3;while(1) for(m=c;mn) / 满足条件即行输出 printf(“最小的%d 个连续合数区间为:“,n);printf(“%ld,%ld。 n“,f+1,f+n);getch();return;if(t=0) f=m; / 每求出一个素数 m 后赋值给 f if(md)c=d+2;d=c+10000; / 每一轮试商后改变 c,d 转下一轮 4 程序运行示例求最小的 n 个连续合数,输入 n(2-100): 5020最小的 50 个连

22、续合数区间为:19610,19659。求最小的 n 个连续合数,输入 n(2-100): 100最小的 100 个连续合数区间为: 370262,370361。建议:运行前面求区间素数的程序验证这些区间上是否存在素数。2.7 三阶素数方阵通常的 n 阶幻方由 1,2,.,n2构成的各行、各列与两对角线之和均相等 n 行 n 列方阵。素数幻方全是由素数构成的各行、各列与两对角线之和均相等方阵。2.7.1 指定区间的三阶素数方阵1. 案例提出试在区间300,600找出 9 个素数,构成一个 3 阶素数幻方,使得该方阵中 3 行、3列与两对角线上的 3 个数之和均相等。2. 设计要点试在一般区间c,

23、d找出 9 个素数,构成一个 3 阶素数幻方,使得该方阵中 3 行、3列与两对角线上的 3 个数之和均相等。如果有解,统计有多少个解?这是一个新颖的有一定难度的问题。设置 a 数组,数组元素清“0” 。通过试商判别,寻找出c,d中的所有素数 k,并标注 ak=1,为以后的判断提供依据。设方阵正中间数为 n,幻和(即每行,每列与每对角线之和)为 s。注意到(中间一行)+(中间一列)+2*(两对角线)=6s(上下行)+(左右列)=4s两式相减即得6n=2s n=s/3这意味着凡含 n 的行或列或对角线的三数中,除 n 之外的另两数与 n 相差等距。为此,设方阵为: n-x n+w n-yn+z n

24、 n-zn+y n-w n+x同时设方阵的两对角线的三数为大数在下(即 x,y0),下面一行三数为大数在右(即 xy)。这样约定是避免重复统计解。显见,上述 33 方阵的中间一行,中间一列与两对角线上三数之和均为 3n。要使左右两列,上下两行的三数之和也为 3n,当且仅当21z=x-yw=x+y (xy)同时易知 9 个素数中不能有偶素数 2,因而 x,y,z,w 都只能是正偶数。 穷举c,d中的素数 n,穷举 y,x,并按上述两式得 z,w:若出现 x=2y,将导致 z=y,方阵中出现两对相同的数,显然应予排除。显然 n-w 是 9 个数中最小的,n+w 是 9 个数中最大的。若 n-wd,

25、已超出c,d界限,应予以排除。另外,由于 n+xd 且 n+yd 且 xy,所以 yd-n-1 和 xd-n。检测方阵中其他 8 个数是否是素数,引用变量 t1,t2,t1*t2 为 8 个数的标记之积。若 t1*t2=0,即 8 个数中存在非素数,返回。否则,已找到一个三阶素数幻方解,按方阵格式输出并用变量 m 统计基本解的个数。这样处理,能较快的找出所有解,既无重复,也没有遗漏。3. 三阶素数幻方程序设计/ 指定区间内素数构造三阶素数幻方 #include #includevoid main()int c,d,j,k,n,t,t1,t2,w,x,y,z,m=0;int a3000;prin

26、tf(“ 请确定区间下限 c,上限 d: “);scanf(“%d,%d“,if(c%2=0) c=c+1;for(k=c;kd) continue; / 控制幻方的素数范围 t1=an-w*an+w*an-z*an+z;t2=an-x*an+x*an-y*an+y;22if(t1*t2=0) continue; / 控制其余 8 个均为素数 m+; printf(“NO %d:n“,m); / 统计并输出三阶素数幻方 printf(“%5d%5d%5dn“,n-x,n+w,n-y);printf(“%5d%5d%5dn“,n+z,n,n-z);printf(“%5d%5d%5dn“,n+y,

27、n-w,n+x);printf(“n 共 %d 个素数方阵.n“,m);4. 程序运行示例请确定区间下限 c,上限 d: 300,600NO 1:401 563 419479 461 443503 359 521共 1 个素数方阵. 2.7.2 指定幻和的三阶素数方阵1. 案例提出试寻求 9 个素数,构造一个 3 阶素数幻方,使得该素数方阵中 3 行、3 列与两对角线上的 3 个素数之和均等于给定的整数 s。2. 设计要点按前例构造 9 数组成的方阵。对于键盘输入的整数 s, 如果存在幻和为 s 的素数幻方,则 s 应为中间素数的 3 倍。设 n=s/3,若通过试商知 n 不是素数,显然不存在

28、幻和为 s 的素数幻,显示“此时无解!”后结束。若 n=s/3 是一个素数,确定素数幻方中素数取值的上限 d=s-8,并在3,d范围内确定 x,y,w,z,并检测 8 个数 n-x,n+w,n-y,n+z,n-z,n+y,n-w,n+x 是否同时为素数。若同时为素数,即可按以上规定作输出,并用 m 统计解的个数。3. 程序实现/ 指定幻和的三阶素数幻方 #include #includevoid main()int c,d,j,k,n,t,t1,t2,s,w,x,y,z,m;int a3000;23printf(“ 请确定素数幻方的幻和 s: “);scanf(“%d“,n=s/3;m=0;c

29、=3;d=s-8; / 确定幻和为 s 时素数的最大最小区间 for(k=c;kd) continue; / 控制幻方的素数范围 t1=an-w*an+w*an-z*an+z;t2=an-x*an+x*an-y*an+y;if(t1*t2=0) continue; / 控制其余 8 个均为素数 m+; printf(“NO %d:n“,m); / 统计并输出三阶素数幻方 printf(“%5d%5d%5dn“,n-x,n+w,n-y);printf(“%5d%5d%5dn“,n+z,n,n-z);printf(“%5d%5d%5dn“,n+y,n-w,n+x); printf(“n 共 %d

30、个素数方阵.n“,m);4. 程序运行示例请确定素数幻方的幻和 s: 789NO 1:173 359 257347 263 179269 167 353NO 2:137 419 233359 263 16724293 107 389共 2 个素数方阵.2.8 穷举设计的改进与优化应用穷举设计求解比较简单,不存在太多难点,但也不能太随意。实际上,穷举结构的设置,穷举参数的选取,都有很多值得我们观注与思考的地方,自然也存在很多改进与优化的空间。2.8.1 整币兑零1. 案例提出计算把一张 1 元整币兑换成 1 分、2 分、5 分、1 角、2 角和 5 角共 6 种零币的不同兑换种数。进一步计算把一

31、张 2 元整币与一张 5 元整币兑换成上述 6 种零币的不同兑换种数。2. 穷举设计求解设整币的面值为 n 个单位,面值为 1、2、5、10、20、50 单位零币的个数分别为 p1, p2, p3, p4, p5, p6。显然需解一次不定方程p1+2*p2+5*p3+10*p4+20*p5+50*p6=n (p1, p2, p3, p4, p5, p6 为非负整数)对这 6 个变量实施穷举,确定穷举范围为 0p1n, 0p2n/2, 0p3n/5, 0p4n/10, 0p5n/20, 0p6n/50。在以上穷举的 6 重循环中,若满足条件p1+2*p2+5*p3+10*p4+20*p5+50*

32、p6=n则为一种兑零方法,输出结果并通过变量 m 增 1 统计不同的兑换种数。3. 穷举求解 C 程序设计/ 整币兑零穷举设计 1 #include void main()int p1,p2,p3,p4,p5,p6,n;long m=0;printf(“n n=“);scanf(“%d“,printf(“ 1 分 2 分 5 分 1 角 2 角 5 角 n“);for(p1=0;p1void main()int p1,p2,p3,p4,p5,p6,n; long m=0;printf(“n n=“);scanf(“%d“,printf(“ 1 分 2 分 5 分 1 角 2 角 5 角 n“)

33、;for(p2=0;p2=0)m+;printf(“ %5d%5d%5d“,p1,p2,p3);printf(“%5d%5d%5dn“,p4,p5,p6);26printf(“ %d(1,2,5,10,20,50)=%ld n“,n,m);运行程序,输入 200,即得 2 元整币兑换成 1 分,2 分,5 分,1 角,2 角,5 角共 6种零币的不同兑换种数为200(1,2,5,10,20,50)=69118精简穷举循环设计使穷举循环次数缩减为以上设计的 1/n。5. 穷举设计的进一步优化以上程序的循环次数已经大大精简了。进一步的分析,我们看到在程序的循环设置中,p3 循环从 0n/5 可改进

34、为 0(n-2 *p2)/5,因为在 n 中 p2 已占去了 2*p2。依此类推,对 p4, p5, p6 的循环可作类似的循环参量优化。/ 优化穷举设计 3 #include void main()int p1,p2,p3,p4,p5,p6,n; long m=0;printf(“n n=“);scanf(“%d“,printf(“ 1 分 2 分 5 分 1 角 2 角 5 角 n“);for(p2=0;p2=0)m+;printf(“ %5d%5d%5d“,p1,p2,p3);printf(“%5d%5d%5dn“,p4,p5,p6);printf(“ %d(1,2,5,10,20,50

35、)=%ld n“,n,m);运行程序,输入 n=500,即得 5 元整币兑换成 1 分、2 分、5 分、1 角、2 角、5 角共6种零币的不同兑换种数为500(1,2,5,10,20,50)=39372566. 以上 3 个穷举设计比较以上 3 个穷举求解程序体现了程序的改进与优化过程,因循环设置的差异与循环参量的不同,直接影响程序求解的速度。由以上穷举设计 1 到精简循环改进设计 2,到进一步优化设计 3,循环次数逐步精简,程序运行时间逐步缩减。测试 3 个穷举算法中条件判断语句执行次数如表 2.1 所示。27表 2.1 3 个穷举算法中条件判断语句执行次数比较n 取值 100 200 50

36、0整币兑零穷举设计 1 21 417 858 961 353 855 1.8e+11精简循环设计 2 212 058 4 782 855 369 769 686优化穷举设计 3 4 562 69 118 3 937 256由表 2.1 所列举的数据可见,求解同一个问题的穷举设计,精简循环的求解时间缩减为原穷举设计的数百分之一,而优化算法的求解时间缩减为精简循环设计的数百分之一。由此可见,算法的改进与优化对于提高求解效率的作用。由于穷举计算所需的时间随 n 增加而迅速增加,以致当 n 比较大或所兑零币种数增多时求解变得无望,改进算法才能快速解决整币兑零种数问题。2.8.2 完美综合式1. 案例提

37、出把数字 1,2,.,9 这 9 个数字填入以下含加减乘除与乘方的综合运算式中的 9 个中,使得该式成立+-=0 要求数字 1,2,.,9 这 9 个数字在各式中都出现一次且只出现一次,且约定数字“1”不出现在乘、乘方的一位数中(即排除各式中的各个 1 位数为 1 这一平凡情形) 。2. 设计要点式中含有加减乘除与乘方 5 种运算,求解难度更大些。设式右的 6 个整数从左至右分别为 a,b,z,c,d,e,其中 z,c,d 为 2 位整数,a,b,e 为大于 1 的一位整数。因式中有乘方,6 个变量设置为 double 型。设置 a,b,c,d,e,z 循环,对每一组 a,b,c,d,e,z,

38、进行以下检测:(1)若 z 不是 c 的倍数, 即 fmod(z,c)!=0,则返回继续;(2)若等式不成立,即 pow(a,b)+z/c!=d*e, 则返回继续;(3)式中 9 个数字是否存在相同数字。对 6 个整数共 9 个数字进行分离,分别赋值给数组 f1f9。连同附加的 f0=0,共 10 个数字在二重循环中逐个比较:若存在相同数字,t=1,不作输出。若不存在相同,即式中 9 个数字为 19 不重复,保持标记 t=0, 则输出所得的完美综合运算式。设置 n 统计解的个数。3. 程序实现/ 含乘方的完美综合运算式 #include 28#include void main()double

39、 a,b,c,d,e,z;int j,k,t,n,f11;printf(“ +/-*=0 n“);n=0;for(a=2;a#include void main()int a,b,c,d,e,k,t,n,x,y,z,m7,f10;printf(“ +/-*=0 n“);n=0;for(a=2;a98) continue;m1=a;m2=b;m3=c;m4=d;m5=e;m6=z;for(x=0;x0) x=y%10;fx=fx+1;y=y/10; / 分离数字 f 数组统计 for(t=0,x=1;x=9;x+)if(fx!=1) t=1;break; / 检验数字 1-9 各出现一次 if(

40、t=0) / 输出一个解,用 n 统计个数 n+; 30printf(“%2d: %d%d+%d/%d“,n,a,b,z,c);printf(“-%d*%d=0 n“,d,e); 优化程序还是得到以上三个解,但可读性好,且运行要快得多。2.8.3 和积三角形1. 案例提出把和为正整数 s(s36)的 8 个互不相等的正整数填入 8 数字三角形(如图 1 所示)中,若三角形三边上的数字之和相等(s1)且三边上的数字之积也相等(s2),该三角形称为和积三角形。图 1 8 数字三角形 1) 存在和积三角形,s 至少为多大? 写出此时的和积三角形。2) s=89 时存在多少个不同的和积三角形? 分别写出此时的和积三角形。2. 求解要点把和为 s 的 8 个正整数存储于 b 数组 b(1),b(8),分布如图 2 所示。为避免重复,不妨约定三角形中数字“下小上大、左小右大” ,即 b(1)b(7)且 b(2)b(3)且 b(6)b(5)。b(4)b(3) b(5)b(2) b(6)b(1) b(8) b(7)图 2 b 数组分布示意图可以根据约定对 b(1)、b(7)的值进行循环探索,设置:b(1)的取值范围为 1(s-21)/2;(因除 b(1),b(4)外其他 6 个数之和至少为 21)

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

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报