蛮力算法
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
5
算法设计2: 在公鸡(x)、母鸡(y)的数量确定后,小鸡的数量 z就固定为100-x-y,无需再进行枚举了。 此时约束条件只有一个: 5*x+3*y+z/3=100.
6Biblioteka Baidu
main( ) { int x,y,z; for(x=1;x<=20;x=x+1) for(y=1;y<=33;y=y+1) { z=100-x-y; if(z mod 3=0 and 5*x+3*y+z/3=100) {print("the cock number is",x); print("the hen number is", y);
16
算法设计1: 1)用n个空间的一维数组a[n],每个元素记录一个锁的状 态,1为被锁上,0为被打开。 2)用数学运算方便模拟开关锁的技巧,对i号锁的一次开 关锁可以转化为算术运算:a[i]=1-a[i]。 3)第一次转动的是1,2,3,„„n号牢房; 第二次转动的是2,4,6,„„号牢房; 第三次转动的是3,6,9,„„号牢房; „„ 第 i 次转动的是 i , 2i , 3i , 4i ,„„号牢房,是起点 为i,公差为i的等差数列。 4)不做其它的优化,用蛮力法通过循环模拟狱吏的开关 锁过程,最后当第i号牢房对应的数组元素a[i]为0 时,该牢房的囚犯得到大赦。
9
算法设计 2 :将算式变形为除法: DDDDDD/A=ABCAB 。 此时只需枚举 A: 3——9 D:1——9,共尝试 7*9=63
次。每次尝试,测试商的万位、十位与除数是否相
同,千位与个位是否相同,都相同时为解。
10
main() {int A,B,C,D,E,F; for(A=3;A<=9;A++) for(D=1;D<=9;D++) { E = D*100000+D*10000+D*1000+D*100+D*10+D; if(E mod A=0) F=E\A; if(F\10000=A and (F mod 100)\10=A) and (F\1000=F mod 10) print( F,”*”,A,”=”,E); } }
14
算法如下: main( ) {int i,j,a[100][100],n; input(n); for(i=1;i<=n;i=i+1) for(j=1;j<=n;j=j+1) {if (i=j or i+j=n+1) a [i][j]=0; if (i+j<n+1 and i<j) a [i][j]=1; if (i+j<n+1 and i>j) a [i][j]=2; if (i+j>n+1 and i>j) a [i][j]=3; if (i+j>n+1 and i<j) a [i][j]=4;} for(i=1;i<=n;i=i+1) { print( “换行符”); for( j=1;j<=n;j=j+1) print(a[i][j]); } }
print("the chick number is ",z);} } } 算法分析:以上算法只需枚举尝试20*33=660次。实现时约束条 件限定Z能被3整除时,才判断“5*x+3*y+z/3=100”。这样省去 了z不整除3时的算术运算和条件判断,进一步提高了算法效率。
7
【例3.2】解数字迷
A
13
2
3 ) 用 i 代表行下标,以 j 代表列下标(除特别声明以后都 遵守此约定),则对n*n矩阵有以下常识: 主对角线元素:i=j; 副对角线元素:下标下界为1时i+j=n+1; 下标下界为0时i+j=n-1; 主上三角◥元素: i <=j; 主下三角◣元素: i >=j; 次上三角◤元素:下标下界为1时i+j<=n+1, 下标下界为0时i+j<=n-1; 次下三角◢元素:下标下界为1时i+j>=n+1, 下标下界为0时i+j>=n-1;
B D
C D
A
×
D D
B A D D
算法设计1:按乘法枚举 A=1,2时积不 1)枚举范围为: 会得到六位 A:3——9,B:0——9,C:0——9 数 六位数表示:A*10000+B*1000+C*100+A*10+B,尝试700次。 2)约束条件为: 每次尝试,先求六位数与A的积,再测试积的各位是否相 同,若相同则找到了问题的解。 测试积的各位是否相同比较简单的方法是,从低位开始, 每次都取数据的个位,然后整除10,使高位的数字不断变 成个位,并逐一比较。
蛮力法并不总是因为减少了人脑的思维,就一 定是效率差的算法。对规模不是太大的问题, 蛮力法还是一种比较好的算法策略。
21
表3.1
n d(n) 1 1 2 2 3 2 4 3 5 2 6 4
编号与因数个数的关系
7 2 8 4 9 3 10 4 11 2 12 6 13 2 14 4 15 4 16 „„ 5 „„
2
1 枚举法
枚举法(穷举法)是蛮力策略的一种表现形式,根据问题 中条件将可能情况一一列举出来,逐一尝试从中找出满足 问题条件的解。但有时一一列举出的情况数目很大,则需 要进一步考虑,排除一些明显不合理的情况,尽可能减少 问题可能解的列举数目。 通常从两个方面进行算法设计: 1)找出枚举范围:分析问题所涉及的各种情况。 2)找出约束条件:分析问题的解需要满足的条件,并 用逻辑表达式表示。
4
算法1如下: 算法分析:此算 法需要枚举尝试 main( ) 20*34*100=68000 { int x,y,z; 次。算法的效率 for(x=1;x<=20;x=x+1) 显然太低。 for(y=1;y<=34;y=y+1) for(z=1;z<=100;z=z+1) if(100=x+y+z and 100=5*x+3*y+z/3) {print("the cock number is",x); print("the hen number is", y); print("the chick number is ",z); } }
表3.1
n d(n)
编号与因数个数的关系
11 12 13 14 15 16 „„ 2 6 2 4 4 5 „„
1 2 3 4 5 6 7 8 9 10 1 2 2 3 2 4 2 4 3 4
数学模型2:d(n)有的为奇数,有的为偶数,由于牢房的门开 始是关着的,这样编号为i的牢房,所含1——i之间的不重复 因子个数为奇数时,牢房最后是打开的;反之,牢房最后是 关闭的。
3
【例3.1】百钱百鸡问题。中国古代数学家张丘建在《算经》 中提出了著名的“百钱百鸡问题”:鸡翁一,值钱五;鸡母一, 值钱三;鸡雏三,值钱一;百钱买百鸡,翁、母、雏各几何? 算法设计1: 通过对问题的理解,可能会想到列出两个三元一次方程, 去解这个不定解方程,就能找出问题的解。这确实是一种办法, 但这里我们要用“懒惰”的枚举策略进行算法设计: 设x,y,z分别为公鸡、母鸡、小鸡的数量。 尝试范围:由题意给定共100钱要买百鸡,若全买公鸡最多 买100/5=20只,显然x的取值范围1~20之间;同理,y的取值范 围在1~33之间,z的取值范围在1~100之间。 约束条件: x+y+z=100 且 5*x+3*y+z/3=100
17
main1( ) { int *a,i,j,n; input(n); a=calloc(n+1,sizeof(int)); //申请存储空间 for (i=1; i<=n;i++) a[i]=1; for (i=1; i<=n;i++) for (j=i; j<=n;j=j+i) a[i]=1-a[i]; for (i=1; i<=n;i++) if (a[i]=0) print(i,”is free.”); } 算法分析1:以一次开关锁计算,算法的时间复杂度为 n(1+1/2+1/3+……+1/n)=O(nlogn)。
20
算法分析2:
狱吏开关锁的主要操作是a[i]=1- a[i];共执行 n*(1+1/2+1/3+……+1/n)次,时间复杂度近似为O (n logn)。使用了n个空间的一维数组。算法2没 有使用辅助空间,但由于求一个编号的因子个数也 很复杂,其主要操作是判断i mod j是否为0,共执 行了1+2+3+……+n次,时间复杂度为O(n2 /2)。
数学模型3:仔细观察表3.1,发现当且仅当n为完全平方 数时,d(n)为奇数;这是因为n的因子是成对出现的,也即 当n=a*b且a≠b时,必有两个因子a,b; 只有n为完全平方 数,也即当n=a2时,才会出现d(n)为奇数的情形。 算法设计3:只需找出小于n的平方数即可。
8
算法1如下: 算法分析1:该算法 main( ) 的尝试范围是A: { int A,B,C,D,E,E1,F,G1,G2,i; 3—9,B:0—9, C:0—9 。共尝试 for(A=3; A<=9; A++) 700次,不是一个 for(B=0; B<=9; B++) 好的算法。 for(C=0; C<=9; C++) { F=A*10000+B*1000+C*100+A*10+B; E=F*A; E1=E; G1=E1 mod 10; for(i=1; i<=5; i++) { G2=G1; E1=E1/10; G1= E1 mod 10; if(G1<>G2 ) break; } if(i=6) print( F,”*”,A,”=”,E); } }
19
算法设计2: 1)算法是求出每个牢房编号的不重复的因子个数,当它为 奇数时,这里边的囚犯得到大赦。 2)一个数的因子是没有规律的,只能从1——n枚举尝试。 main2( ) { int s,i,j,n; input(n); for (i=1; i<=n;i++) 为什么从2开始? { s=1; for (j=2; j<=i;j=j++) if (i mod j=0) s=s+1; if (s mod 2 =1) print(i,”is free.”); } }
11
【例3.3】编程打印有如下规律的n×n方阵。
例如下图:使左对角线和右对角线上的元素为0,它们 上方的元素为1,左方的元素为2,下方元素为3,右方 元素为4,下图是一个符合条件的5阶矩阵。
0 2 2 2 0 1 0 2 0 3 1 1 0 3 3 1 0 4 0 3 0 4 4 4 0
12
构造趣味矩阵:经常用二维数组来解决
18
问题分析2:转动门锁的规则可以有另一种理解,第一次转动 的是编号为1的倍数的牢房;第二次转动的是编号为2的倍数 的牢房;第三次转动的是编号为3的倍数的牢房;„„则狱吏 问题是一个关于因子个数的问题。 令d(n)为自然数n的因子个数,这里不计重复的因子,如4 的因子为1,2,4共三个因子,而非1,2,2,4。则d(n)或为 奇数,或为偶数,见下表:
蛮力法
1
蛮力法
蛮力法是基于计算机运算速度快这一特性,在解决问题 时采取的一种“懒惰” 策略。这种策略不经过(或者说经过 很少)思考,把问题所有情况或所有过程交给计算机去一 一尝试,从中找出问题的解。
蛮力策略应用:选择排序、冒泡排序、插入排序、顺序 查找、朴素的字符串匹配等。比较常用还有枚举法、盲目 搜索算法等。
根据趣味矩阵中的数据规律,设计算法把要输出的数据 存储到一个二维数组中,最后按行输出该数组中的元素。 基本常识: 1)当对二维表按行进行操作时,应该“外层循环控制行; 内层循环控制列”;反之若要对二维表按列进行操作时,应 该“外层循环控制列;内层循环控制行”。 2)二维表和二维数组的显示输出,只能按行从上到下连续 进行,每行各列则只能从左到右连续输出。所以,只能用“ 外层循环控制行;内层循环控制列”。
15
【例3.5】狱吏问题 某国王对囚犯进行大赦,让一狱吏n次通过一排锁着 的n间牢房,每通过一次,按所定规则转动n间牢房中的某 些门锁, 每转动一次, 原来锁着的被打开, 原来打开的被 锁上;通过n次后,门锁开着的,牢房中的犯人放出,否则 犯人不得获释。 转动门锁的规则是这样的,第一次通过牢房,要转动 每一把门锁,即把全部锁打开;第二次通过牢房时,从第 二间开始转动,每隔一间转动一次;第k次通过牢房,从第 k间开始转动,每隔k-1 间转动一次;问通过n次后,哪些 牢房的锁仍然是打开的?
算法设计2: 在公鸡(x)、母鸡(y)的数量确定后,小鸡的数量 z就固定为100-x-y,无需再进行枚举了。 此时约束条件只有一个: 5*x+3*y+z/3=100.
6Biblioteka Baidu
main( ) { int x,y,z; for(x=1;x<=20;x=x+1) for(y=1;y<=33;y=y+1) { z=100-x-y; if(z mod 3=0 and 5*x+3*y+z/3=100) {print("the cock number is",x); print("the hen number is", y);
16
算法设计1: 1)用n个空间的一维数组a[n],每个元素记录一个锁的状 态,1为被锁上,0为被打开。 2)用数学运算方便模拟开关锁的技巧,对i号锁的一次开 关锁可以转化为算术运算:a[i]=1-a[i]。 3)第一次转动的是1,2,3,„„n号牢房; 第二次转动的是2,4,6,„„号牢房; 第三次转动的是3,6,9,„„号牢房; „„ 第 i 次转动的是 i , 2i , 3i , 4i ,„„号牢房,是起点 为i,公差为i的等差数列。 4)不做其它的优化,用蛮力法通过循环模拟狱吏的开关 锁过程,最后当第i号牢房对应的数组元素a[i]为0 时,该牢房的囚犯得到大赦。
9
算法设计 2 :将算式变形为除法: DDDDDD/A=ABCAB 。 此时只需枚举 A: 3——9 D:1——9,共尝试 7*9=63
次。每次尝试,测试商的万位、十位与除数是否相
同,千位与个位是否相同,都相同时为解。
10
main() {int A,B,C,D,E,F; for(A=3;A<=9;A++) for(D=1;D<=9;D++) { E = D*100000+D*10000+D*1000+D*100+D*10+D; if(E mod A=0) F=E\A; if(F\10000=A and (F mod 100)\10=A) and (F\1000=F mod 10) print( F,”*”,A,”=”,E); } }
14
算法如下: main( ) {int i,j,a[100][100],n; input(n); for(i=1;i<=n;i=i+1) for(j=1;j<=n;j=j+1) {if (i=j or i+j=n+1) a [i][j]=0; if (i+j<n+1 and i<j) a [i][j]=1; if (i+j<n+1 and i>j) a [i][j]=2; if (i+j>n+1 and i>j) a [i][j]=3; if (i+j>n+1 and i<j) a [i][j]=4;} for(i=1;i<=n;i=i+1) { print( “换行符”); for( j=1;j<=n;j=j+1) print(a[i][j]); } }
print("the chick number is ",z);} } } 算法分析:以上算法只需枚举尝试20*33=660次。实现时约束条 件限定Z能被3整除时,才判断“5*x+3*y+z/3=100”。这样省去 了z不整除3时的算术运算和条件判断,进一步提高了算法效率。
7
【例3.2】解数字迷
A
13
2
3 ) 用 i 代表行下标,以 j 代表列下标(除特别声明以后都 遵守此约定),则对n*n矩阵有以下常识: 主对角线元素:i=j; 副对角线元素:下标下界为1时i+j=n+1; 下标下界为0时i+j=n-1; 主上三角◥元素: i <=j; 主下三角◣元素: i >=j; 次上三角◤元素:下标下界为1时i+j<=n+1, 下标下界为0时i+j<=n-1; 次下三角◢元素:下标下界为1时i+j>=n+1, 下标下界为0时i+j>=n-1;
B D
C D
A
×
D D
B A D D
算法设计1:按乘法枚举 A=1,2时积不 1)枚举范围为: 会得到六位 A:3——9,B:0——9,C:0——9 数 六位数表示:A*10000+B*1000+C*100+A*10+B,尝试700次。 2)约束条件为: 每次尝试,先求六位数与A的积,再测试积的各位是否相 同,若相同则找到了问题的解。 测试积的各位是否相同比较简单的方法是,从低位开始, 每次都取数据的个位,然后整除10,使高位的数字不断变 成个位,并逐一比较。
蛮力法并不总是因为减少了人脑的思维,就一 定是效率差的算法。对规模不是太大的问题, 蛮力法还是一种比较好的算法策略。
21
表3.1
n d(n) 1 1 2 2 3 2 4 3 5 2 6 4
编号与因数个数的关系
7 2 8 4 9 3 10 4 11 2 12 6 13 2 14 4 15 4 16 „„ 5 „„
2
1 枚举法
枚举法(穷举法)是蛮力策略的一种表现形式,根据问题 中条件将可能情况一一列举出来,逐一尝试从中找出满足 问题条件的解。但有时一一列举出的情况数目很大,则需 要进一步考虑,排除一些明显不合理的情况,尽可能减少 问题可能解的列举数目。 通常从两个方面进行算法设计: 1)找出枚举范围:分析问题所涉及的各种情况。 2)找出约束条件:分析问题的解需要满足的条件,并 用逻辑表达式表示。
4
算法1如下: 算法分析:此算 法需要枚举尝试 main( ) 20*34*100=68000 { int x,y,z; 次。算法的效率 for(x=1;x<=20;x=x+1) 显然太低。 for(y=1;y<=34;y=y+1) for(z=1;z<=100;z=z+1) if(100=x+y+z and 100=5*x+3*y+z/3) {print("the cock number is",x); print("the hen number is", y); print("the chick number is ",z); } }
表3.1
n d(n)
编号与因数个数的关系
11 12 13 14 15 16 „„ 2 6 2 4 4 5 „„
1 2 3 4 5 6 7 8 9 10 1 2 2 3 2 4 2 4 3 4
数学模型2:d(n)有的为奇数,有的为偶数,由于牢房的门开 始是关着的,这样编号为i的牢房,所含1——i之间的不重复 因子个数为奇数时,牢房最后是打开的;反之,牢房最后是 关闭的。
3
【例3.1】百钱百鸡问题。中国古代数学家张丘建在《算经》 中提出了著名的“百钱百鸡问题”:鸡翁一,值钱五;鸡母一, 值钱三;鸡雏三,值钱一;百钱买百鸡,翁、母、雏各几何? 算法设计1: 通过对问题的理解,可能会想到列出两个三元一次方程, 去解这个不定解方程,就能找出问题的解。这确实是一种办法, 但这里我们要用“懒惰”的枚举策略进行算法设计: 设x,y,z分别为公鸡、母鸡、小鸡的数量。 尝试范围:由题意给定共100钱要买百鸡,若全买公鸡最多 买100/5=20只,显然x的取值范围1~20之间;同理,y的取值范 围在1~33之间,z的取值范围在1~100之间。 约束条件: x+y+z=100 且 5*x+3*y+z/3=100
17
main1( ) { int *a,i,j,n; input(n); a=calloc(n+1,sizeof(int)); //申请存储空间 for (i=1; i<=n;i++) a[i]=1; for (i=1; i<=n;i++) for (j=i; j<=n;j=j+i) a[i]=1-a[i]; for (i=1; i<=n;i++) if (a[i]=0) print(i,”is free.”); } 算法分析1:以一次开关锁计算,算法的时间复杂度为 n(1+1/2+1/3+……+1/n)=O(nlogn)。
20
算法分析2:
狱吏开关锁的主要操作是a[i]=1- a[i];共执行 n*(1+1/2+1/3+……+1/n)次,时间复杂度近似为O (n logn)。使用了n个空间的一维数组。算法2没 有使用辅助空间,但由于求一个编号的因子个数也 很复杂,其主要操作是判断i mod j是否为0,共执 行了1+2+3+……+n次,时间复杂度为O(n2 /2)。
数学模型3:仔细观察表3.1,发现当且仅当n为完全平方 数时,d(n)为奇数;这是因为n的因子是成对出现的,也即 当n=a*b且a≠b时,必有两个因子a,b; 只有n为完全平方 数,也即当n=a2时,才会出现d(n)为奇数的情形。 算法设计3:只需找出小于n的平方数即可。
8
算法1如下: 算法分析1:该算法 main( ) 的尝试范围是A: { int A,B,C,D,E,E1,F,G1,G2,i; 3—9,B:0—9, C:0—9 。共尝试 for(A=3; A<=9; A++) 700次,不是一个 for(B=0; B<=9; B++) 好的算法。 for(C=0; C<=9; C++) { F=A*10000+B*1000+C*100+A*10+B; E=F*A; E1=E; G1=E1 mod 10; for(i=1; i<=5; i++) { G2=G1; E1=E1/10; G1= E1 mod 10; if(G1<>G2 ) break; } if(i=6) print( F,”*”,A,”=”,E); } }
19
算法设计2: 1)算法是求出每个牢房编号的不重复的因子个数,当它为 奇数时,这里边的囚犯得到大赦。 2)一个数的因子是没有规律的,只能从1——n枚举尝试。 main2( ) { int s,i,j,n; input(n); for (i=1; i<=n;i++) 为什么从2开始? { s=1; for (j=2; j<=i;j=j++) if (i mod j=0) s=s+1; if (s mod 2 =1) print(i,”is free.”); } }
11
【例3.3】编程打印有如下规律的n×n方阵。
例如下图:使左对角线和右对角线上的元素为0,它们 上方的元素为1,左方的元素为2,下方元素为3,右方 元素为4,下图是一个符合条件的5阶矩阵。
0 2 2 2 0 1 0 2 0 3 1 1 0 3 3 1 0 4 0 3 0 4 4 4 0
12
构造趣味矩阵:经常用二维数组来解决
18
问题分析2:转动门锁的规则可以有另一种理解,第一次转动 的是编号为1的倍数的牢房;第二次转动的是编号为2的倍数 的牢房;第三次转动的是编号为3的倍数的牢房;„„则狱吏 问题是一个关于因子个数的问题。 令d(n)为自然数n的因子个数,这里不计重复的因子,如4 的因子为1,2,4共三个因子,而非1,2,2,4。则d(n)或为 奇数,或为偶数,见下表:
蛮力法
1
蛮力法
蛮力法是基于计算机运算速度快这一特性,在解决问题 时采取的一种“懒惰” 策略。这种策略不经过(或者说经过 很少)思考,把问题所有情况或所有过程交给计算机去一 一尝试,从中找出问题的解。
蛮力策略应用:选择排序、冒泡排序、插入排序、顺序 查找、朴素的字符串匹配等。比较常用还有枚举法、盲目 搜索算法等。
根据趣味矩阵中的数据规律,设计算法把要输出的数据 存储到一个二维数组中,最后按行输出该数组中的元素。 基本常识: 1)当对二维表按行进行操作时,应该“外层循环控制行; 内层循环控制列”;反之若要对二维表按列进行操作时,应 该“外层循环控制列;内层循环控制行”。 2)二维表和二维数组的显示输出,只能按行从上到下连续 进行,每行各列则只能从左到右连续输出。所以,只能用“ 外层循环控制行;内层循环控制列”。
15
【例3.5】狱吏问题 某国王对囚犯进行大赦,让一狱吏n次通过一排锁着 的n间牢房,每通过一次,按所定规则转动n间牢房中的某 些门锁, 每转动一次, 原来锁着的被打开, 原来打开的被 锁上;通过n次后,门锁开着的,牢房中的犯人放出,否则 犯人不得获释。 转动门锁的规则是这样的,第一次通过牢房,要转动 每一把门锁,即把全部锁打开;第二次通过牢房时,从第 二间开始转动,每隔一间转动一次;第k次通过牢房,从第 k间开始转动,每隔k-1 间转动一次;问通过n次后,哪些 牢房的锁仍然是打开的?