其实这个题目我一直没想好应该叫什么,就是在做蓝桥杯的时候会遇到很多的题,给你一等式,abcdef...分别是1-9(||12||15)不重复问你有几种方案?
我之前一直都是用的for循环在做,听说这叫什么暴力破解还是枚举法的。小白不是很懂这些。
但是之前做过一道题,好像就是15个数的for循环写的,一个是巨累(因为我用a!=b&&a!=c&&a!=....真的特别多而且容易写错),另一个是我记得我这道题写了很久最后提交没有分数,因为!!!超时了!!!
真的特别气,当时的我只会做一种题就是for循环的这个,我觉得自己要凉凉了,唯一会的题还超时了。所以痛定思痛,自己去网上down了全排列+dfs的代码。
恰巧这次的代码特别合适,我竟然看懂了(我以前也百度过,但是不记得为什么没有看懂,坚信我们for循环可以打天下的一直没有再去看),而且真的是要特别的夸一夸这一套代码,因为我之后所以的这种题,靠的都是这一套代码。特别省事,差不多可以算是我唯一的模板了。
昨天的题有一道这样的,然后就想把我会的所有的方法整理出来,当然,模板万岁啊。但是如果有时间走两套程序的话,算是检查了,保证准确率。
标题: 马虎的算式
小明是个急性子,上小学的时候经常把老师写在黑板上的题目抄错了。 有一次,老师出的题目是:36 x 495 = ? 他却给抄成了:396 x 45 = ? 但结果却很戏剧性,他的答案竟然是对的!! 因为 36 * 495 = 396 * 45 = 17820 类似这样的巧合情况可能还有很多,比如:27 * 594 = 297 * 54 假设 a b c d e 代表1~9不同的5个数字(注意是各不相同的数字,且不含0) 能满足形如: ab * cde = adb * ce 这样的算式一共有多少种呢?(满足乘法交换律的算式计为不同的种类,所以答案肯定是个偶数。)
第一种方法:最简单的for循环法。最起码10以内很简单不会超时,只要仔细就不会出错
1 public class Main { 2 3 public static void main(String[] args) { 4 //2.能满足形如:ab * cde = adb * ce这样的算式一共有 ?种 5 int a,b,c,d,e; 6 int count=0; 7 for(a=1;a<10;a++){ 8 for(b=1;b<10;b++){ 9 for(c=1;c<10;c++){ 10 for(d=1;d<10;d++){ 11 for(e=1;e<10;e++){ 12 int x=(10*a+b)*(100*c+10*d+e); 13 int y=(100*a+10*d+b)*(10*c+e); 14 if(x==y&& 15 a!=b&&a!=c&&a!=d&&a!=e&& 16 b!=a&&b!=c&&b!=d&&b!=e&& 17 c!=a&&c!=b&&c!=d&&c!=e&& 18 d!=a&&d!=b&&d!=c&&d!=e&& 19 e!=a&&e!=b&&e!=c&&e!=d ){ 20 count++; 21 } 22 } 23 } 24 } 25 } 26 } 27 System.out.println(count); 28 29 } 30 31 }
ps:谁能想到,我第一次这个题写错了呢,因为我忽略了这句话,忘了判断是否是不同的数字了。--->假设 a b c d e 代表1~9不同的5个数字(注意是各不相同的数字,且不含0)在一个是,我看到题目中说--->满足乘法交换律的算式计为不同的种类,所以答案肯定是个偶数。我做的时候没有判断是否不同数字,所以答案是1007,所以,我看到这句话,更加确定了,我做的真对啊。我以为他这句话是在提醒我,*2啊*2啊。结果当然是错的啦。他写这句话应该就是单纯的帮你减轻负担啊,不用考虑交换律的问题,这样出来多少就是多少了。
第二种方法:for循环法稍作改变。新建一个used数组,分别对应1 2 3 4.。。9然后用used数组的值标记是否使用过了。记得在这一轮的for循环最后释放哦。
1 public class Main { 2 3 public static void main(String[] args) { 4 //2.能满足形如:ab * cde = adb * ce这样的算式一共有 ?种 5 int a,b,c,d,e; 6 int count=0; 7 int []used=new int[11]; 8 for(int i=1;i<10;i++){ 9 used[i]=0;//0标记没有用过 1标记用过了 10 } 11 for(a=1;a<10;a++){ 12 used[a]=1; 13 for(b=1;b<10;b++){ 14 if(used[b]==1)continue; 15 used[b]=1; 16 for(c=1;c<10;c++){ 17 if(used[c]==1)continue; 18 used[c]=1; 19 for(d=1;d<10;d++){ 20 if(used[d]==1)continue; 21 used[d]=1; 22 for(e=1;e<10;e++){ 23 if(used[e]==1)continue; 24 used[e]=1; 25 int x=(10*a+b)*(100*c+10*d+e); 26 int y=(100*a+10*d+b)*(10*c+e); 27 if(x==y){ 28 count++; 29 } 30 used[e]=0; 31 } 32 used[d]=0; 33 } 34 used[c]=0; 35 } 36 used[b]=0; 37 } 38 used[a]=0; 39 } 40 System.out.println(count); 41 42 }
这里再备注一下,其实used直接建Boolean比较好,用false true,这样if判断的时候 就不用特意去写了。我这个是因为 我一开始用的boolean 运行的时候有错误,当时做的很烦躁就直接改了int 。之后在别的里面试了boolean完全可以没有问题,可能是其他的地方不知道那里报错了。
第三种方法:全排列+dfs
我其实一开始忘了这个办法,然后翻之前的笔记找到的。先写一下笔记上的原题:
A+B/C+DEF/GHI=0,A-I为1-9不重复,求有几种可满足式子。(DEF=D*100+E*10+F...)
1 public class Main { 2 static int count=0; 3 public static void main(String[] args) { 4 // TODO Auto-generated method stub 5 float a[]=new float[10]; 6 boolean visit[]=new boolean[10]; 7 dfs(a,visit,1); 8 System.out.println(count); 9 } 10 private static void dfs(float[]a,boolean[]visit,int num){ 11 if(num==10){ 12 if(judge(a)){ 13 count++; 14 } 15 return; 16 } 17 for(a[num]=1;a[num]<10;a[num]++){ 18 if(visit[(int)a[num]]==false){ 19 visit[(int)a[num]]=true; 20 num=num+1; 21 dfs(a,visit,num); 22 num=num-1; 23 visit[(int)a[num]]=false; 24 } 25 } 26 } 27 private static boolean judge(float[]a){ 28 float A=a[1]; 29 float B=a[2]/a[3]; 30 float C=a[4]*100+a[5]*10+a[6]; 31 float D=a[7]*100+a[8]*10+a[9]; 32 if(A+B+C/D==10){ 33 return true; 34 } 35 return false; 36 } 37 38 }
然后根据这个写了这道马虎的算式的代码:
1 public class Main { 2 //2.能满足形如:ab * cde = adb * ce这样的算式一共有 ?种 3 static int count=0; 4 public static void main(String[] args) { 5 // TODO Auto-generated method stub 6 float a[]=new float[6];//数组长度由题目中的变量个数决定abcde 5 7 boolean visit[]=new boolean[10]; 8 dfs(a,visit,1); 9 System.out.println(count); 10 } 11 private static void dfs(float[]a,boolean[]visit,int num){ 12 if(num==6){//==前面数组长度 13 if(judge(a)){ 14 count++; 15 } 16 return; 17 } 18 for(a[num]=1;a[num]<10;a[num]++){ 19 if(visit[(int)a[num]]==false){ 20 visit[(int)a[num]]=true; 21 num=num+1; 22 dfs(a,visit,num); 23 num=num-1; 24 visit[(int)a[num]]=false; 25 } 26 } 27 } 28 private static boolean judge(float[]a){ 29 //这一块根据题目自己写 30 //1 2 3 4 5 31 //a b c d e 32 float A=a[1]*10+a[2]; 33 float B=a[3]*100+a[4]*10+a[5]; 34 float C=a[1]*100+a[4]*10+a[2]; 35 float D=a[3]*10+a[5]; 36 if(A*B==C*D){ 37 return true; 38 } 39 return false; 40 } 41 42 }
这个全排列真的挺好用的,而且记住这个模板在做题特别省时间!!而且可以说完全不用过脑子了。
因为为了统一,a[]我就延续用了float,因为这种题真的就是来来回回的*||/所以 用float更放心一些。
补充:
1.拿浮点数进行暴力破解很危险啊,因为浮点数计算有误差!!!
double a =1.0;
double b=0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1;
输出a,b;得到的值是 a->1.0 b->0.999999999999
所以!如果sysout(a==b);必然是false。
2.那么怎么去比较呢?
1.比较a-b是否小于一个比较小的数
System.out.println(Math.abs(a-b)<1e-6);
2.避开浮点数,等式两边同时扩大。
eg:求a*2.3+b*1.9==82.3可以转化成a*23+b*19==823
3.举例:浮点数的运算可以通过变换形式进行
???1/4=0 ==> int/int=int 所以0.25=>(int)0.25=>0
所以,1/a+1/b+1/c=1循环求解的时候可以
1. 1.0/a+1.0/b+1.0/c=1.0 =>这个方法就避免了上面说的int/int =int
2. bc+ac+ab=abc =>这样一转换,就和浮点数没有关系了,就不会影响了
4.举例:特殊值举例
1 System.out.println(3/0); 2 System.out.println(3.0/0);
执行第一行,输出:0不能为分母的英文,报错
执行第二行,输出:Infinity,即无穷大。
why???因为第二行 =>3.0是浮点数(double/float),所以0=>看作了一个0.00000000000....就是一个很很很小的数。3.0/一个很很很小的数===>无穷大
1 double a=3.0/0; 2 System.out.println(a+1); 3 System.out.println(a+a); 4 System.out.println(1/a); 5 System.out.println(1/(-a)); 6 System.out.println(a-a);
输出为:
Infinity
Infinity
0.0
-0.0
NaN
NaN=>not a number,不是一个数值。类似于小学说的无意义。当然NaN+||-一个数也都=NaN
5.任意精度问题(当float 不够->double,double不够?)
举例:有效数字100位(如1/6)
1 BigDecimal a=BigDecimal.valueOf(1).divide(BigDecimal.valueOf(6),new MathContext(100)); 2 System.out.println(a);
输出:0.1666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667
正好做到这里插一个黄金连分数的题当例题了。
1 import java.math.BigDecimal; 2 import java.math.MathContext; 3 4 public class Main { 5 public static void main(String[] args) { 6 // TODO Auto-generated method stub 7 BigDecimal bd = new BigDecimal(1); 8 for (int i = 0; i < 10000; i++) { 9 bd = bd.add(BigDecimal.ONE); 10 // bd = BigDecimal.ONE.divide(bd, 100, BigDecimal.ROUND_HALF_DOWN); 11 bd = BigDecimal.ONE.divide(bd, new MathContext(100)); 12 } 13 System.out.println(bd.toString()); 14 } 15 }
输出:0.6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911375
10 11两行都可以用,答案都是对的。
嗯嗯,终于完成今天的任务了。本来没想写关于浮点数的这些的,没想到写着写着就这么多了。啊,马上10点了,溜了溜了。
原文地址:https://www.cnblogs.com/ShallByeBye/p/8414523.html