1.2枚举与剪枝
暴力破解虽然简单有效,但是有弱点,考虑的情况很多时,计算机承受不了。
人为排除一些不可能的情况。
剪枝就是为了让计算机尽量避免无用的徒劳的动作。
找零方案
要找8元零钱,有零钞:5元,2元,1元,5角
求所有找零方案。
5角如果写成浮点型的,在计算相等的时候会产生误差,所以全部扩大十倍,再进行比较。
/*要找8元零钱,有零钞:5元,2元,1元,5角
求所有找零方案。*/
package ChickRabbit;
public class ChargeCash {
public static void main(String[] args) {
int SUM = 80;// 表示8元
int FIVE = 50;
int TWO = 20;
int ONE = 10;
int FIVEJiao = 5;
for (int a = 0; a <= SUM / FIVE; a++) {
for (int b = 0; b <= SUM / TWO; b++) {
if((SUM-a*FIVE)<0) break;//剪枝
for (int c = 0; c <= SUM / ONE; c++) {
if((SUM - (a * FIVE + b * TWO + c * ONE))<0) break;
int d = (SUM - (a * FIVE + b * TWO + c * ONE)) / 5; // 5角的个数可以用前面的参数表示出来
if (a * FIVE + b * TWO + c * ONE + d * FIVEJiao == SUM) {
System.out.println("可能的找零方案:" + "5元" + a + "张,2元" + b
+ "张,1元" + c + "张,5角" + d + "张");
}
}
}
}
}
}可能的找零方案:5元0张,2元0张,1元0张,5角16张
可能的找零方案:5元0张,2元0张,1元1张,5角14张
可能的找零方案:5元0张,2元0张,1元2张,5角12张
可能的找零方案:5元0张,2元0张,1元3张,5角10张
可能的找零方案:5元0张,2元0张,1元4张,5角8张
可能的找零方案:5元0张,2元0张,1元5张,5角6张
可能的找零方案:5元0张,2元0张,1元6张,5角4张
可能的找零方案:5元0张,2元0张,1元7张,5角2张
可能的找零方案:5元0张,2元0张,1元8张,5角0张
可能的找零方案:5元0张,2元1张,1元0张,5角12张
可能的找零方案:5元0张,2元1张,1元1张,5角10张
可能的找零方案:5元0张,2元1张,1元2张,5角8张
可能的找零方案:5元0张,2元1张,1元3张,5角6张
可能的找零方案:5元0张,2元1张,1元4张,5角4张
可能的找零方案:5元0张,2元1张,1元5张,5角2张
可能的找零方案:5元0张,2元1张,1元6张,5角0张
可能的找零方案:5元0张,2元2张,1元0张,5角8张
可能的找零方案:5元0张,2元2张,1元1张,5角6张
可能的找零方案:5元0张,2元2张,1元2张,5角4张
可能的找零方案:5元0张,2元2张,1元3张,5角2张
可能的找零方案:5元0张,2元2张,1元4张,5角0张
可能的找零方案:5元0张,2元3张,1元0张,5角4张
可能的找零方案:5元0张,2元3张,1元1张,5角2张
可能的找零方案:5元0张,2元3张,1元2张,5角0张
可能的找零方案:5元0张,2元4张,1元0张,5角0张
可能的找零方案:5元1张,2元0张,1元0张,5角6张
可能的找零方案:5元1张,2元0张,1元1张,5角4张
可能的找零方案:5元1张,2元0张,1元2张,5角2张
可能的找零方案:5元1张,2元0张,1元3张,5角0张
可能的找零方案:5元1张,2元1张,1元0张,5角2张
可能的找零方案:5元1张,2元1张,1元1张,5角0张求n的平方尾数仍为n数本身的数字
/*n位数平方的尾数还是自己*/
package ChickRabbit;
public class SameNumber {
public static void main(String[] args) {
// 123*123=.....9
for (int i = 10; i < 100; i++) {
int m = i % 10;
if (m != 0 && m != 1 && m != 5 && m != 6)//只有结尾是0,1,5,6才可以,两位数以上结尾必须是25,76
continue;
int n = i * i;// 平方后
if (n % 100 == i) {// 取余数
System.out.println(i + "," + n);
}
}
}
}25,625
76,5776
改进版,10000以内的所有。
/*n位数平方的尾数还是自己*/
package ChickRabbit;
public class SameNumber {
public static void main(String[] args) {
// 123*123=.....9
for (int i = 0; i < 10000; i++) {
if (i < 10) {
int m = i % 10;
if (m != 0 && m != 1 && m != 5 && m != 6)// 只有结尾是0,1,5,6才可以
continue;
int n = i * i;// 平方后
if (n % 10 == i) {// 取余数
System.out.println(i + "," + n);
}
} else {
int m = i % 100;
if (m != 25 && m != 76)//两位数以上结尾必须是25,76
continue;
int n = i * i;// 平方后
if (i > 9 && i < 100) {
if (n % 100 == i) {// 取余数
System.out.println(i + "," + n);
}
} else if ( i < 1000) {
if (n % 1000 == i) {// 取余数
System.out.println(i + "," + n);
}
} else if ( i < 10000) {
if (n % 10000 == i) {// 取余数
System.out.println(i + "," + n);
}
}
}
}
}
}0,0
1,1
5,25
6,36
25,625
76,5776
376,141376
625,390625
9376,87909376
剪枝就是尽早排除逻辑上不符合要求的情况。特别是在循环嵌套中。
观察算式
观察下面的算式:
△△△ * △△ = △△△△
某3位数乘以2位数,结果为4位数
要求:在9个△所代表的数字中,1~9的数字恰好每个出现1次。
/*观察下面的算式:
△△△ * △△ = △△△△
某3位数乘以2位数,结果为4位数
要求:在9个△所代表的数字中,1~9的数字恰好每个出现1次。
*/
package ChickRabbit;
public class Watch {
public static void main(String[] args) {
int n1, n2, n3, n4, n5, n6, n7, n8, n9;
long t1 = System.currentTimeMillis();
for (int i = 123; i <= 987; i++) {
n1 = i / 100;
n2 = i / 10 % 10;
n3 = i % 10;
if (n1 == 0 || n2 == 0 || n3 == 0 ) {
continue;
}
if( n1 == n2 || n1 == n3
|| n2 == n3){
continue;
}
for (int j = 12; j <= 98; j++) {
n4 = j / 10;
n5 = j % 10;
if (n4 == 0 || n5 == 0 ) {
continue;
}
if( n4 == n5 || n4 == n1 || n4 == n2
|| n4 == n3 || n5 == n1 || n5 == n2 || n5 == n3){
continue;
}
for (int k = 1234; k <= 9876; k++) {
n6 = k / 1000;
n7 = k / 100 % 10;
n8 = k / 10 % 10;
n9 = k % 10;
if((n3*n5)%10!=n9){
continue;
}
if (n6 == 0 || n7 == 0 || n8 == 0 || n9 == 0 || n6 == n7
|| n6 == n8 || n6 == n9 || n7 == n8 || n7 == n9
|| n8 == n9 || n6 == n1 || n6 == n2 || n6 == n3
|| n6 == n4 || n6 == n5 || n7 == n1 || n7 == n2
|| n7 == n3 || n7 == n4 || n7 == n5 || n8 == n1
|| n8 == n2 || n8 == n3 || n8 == n4 || n8 == n5
|| n9 == n1 || n9 == n2 || n9 == n3 || n9 == n4
|| n9 == n5) {
continue;
}
if (i * j == k) {
System.out.println(i + " " + j + " " + k);
}
}
}
}
long t2 = System.currentTimeMillis();
System.out.println(t2 - t1);
}
}138 42 5796
157 28 4396
159 48 7632
186 39 7254
198 27 5346
297 18 5346
483 12 5796
8017
慢的一逼
改进一下:
/*观察下面的算式:
△△△ * △△ = △△△△
某3位数乘以2位数,结果为4位数
要求:在9个△所代表的数字中,1~9的数字恰好每个出现1次。
*/
package ChickRabbit;
public class Watch {
public static void main(String[] args) {
int n1, n2, n3, n4, n5, n6, n7, n8, n9;
long t1 = System.nanoTime();// 测试时间的第一个时间点
for (int i = 123; i <= 987; i++) {
n1 = i / 100;
n2 = i / 10 % 10;
n3 = i % 10;
if (n1 == 0 || n2 == 0 || n3 == 0 || n1 == n2 || n1 == n3
|| n2 == n3) {
continue;
}
for (int j = 12; j <= 98; j++) {
int k = i * j;// 得到4位数的乘积,先得到乘积并对乘积范围进行判断,再取每一位数字,可以提高效率。
if (k <= 9876) {
// 对第二个乘数进行判断
n4 = j / 10;
n5 = j % 10;
if (n4 == 0 || n5 == 0) {
continue;
}
if (n4 == n5 || n4 == n1 || n4 == n2 || n4 == n3
|| n5 == n1 || n5 == n2 || n5 == n3) {
continue;
}
// 对乘积进行判断
n6 = k / 1000;
n7 = k / 100 % 10;
n8 = k / 10 % 10;
n9 = k % 10;
if ((n3 * n5) % 10 != n9 || n6 == 0 || n7 == 0 || n8 == 0
|| n9 == 0 || n6 == n7 || n6 == n8 || n6 == n9
|| n7 == n8 || n7 == n9 || n8 == n9 || n6 == n1
|| n6 == n2 || n6 == n3 || n6 == n4 || n6 == n5
|| n7 == n1 || n7 == n2 || n7 == n3 || n7 == n4
|| n7 == n5 || n8 == n1 || n8 == n2 || n8 == n3
|| n8 == n4 || n8 == n5 || n9 == n1 || n9 == n2
|| n9 == n3 || n9 == n4 || n9 == n5) {
continue;
}
System.out.println(i + "*" + j + "=" + k);
}
}
}
long t2 = System.nanoTime();// 测试时间的第二个时间点
System.out.println(t2 - t1);
}
}
138*42=5796
157*28=4396
159*48=7632
186*39=7254
198*27=5346
297*18=5346
483*12=5796
3043679
改进版2,将判断0的或运算换为乘法。(不知道哪个效率高)
/*观察下面的算式:
△△△ * △△ = △△△△
某3位数乘以2位数,结果为4位数
要求:在9个△所代表的数字中,1~9的数字恰好每个出现1次。
*/
package ChickRabbit;
public class Watch {
public static void main(String[] args) {
int n1, n2, n3, n4, n5, n6, n7, n8, n9;
long t1 = System.nanoTime();// 测试时间的第一个时间点
for (int i = 123; i <= 987; i++) {
n1 = i / 100;
n2 = i / 10 % 10;
n3 = i % 10;
if (n1 * n2 * n3 == 0 || n1 == n2 || n1 == n3 || n2 == n3) {
continue;
}
for (int j = 12; j <= 98; j++) {
int k = i * j;// 得到4位数的乘积,先得到乘积并对乘积范围进行判断,再取每一位数字,可以提高效率。
if (k <= 9876) {
// 对第二个乘数进行判断
n4 = j / 10;
n5 = j % 10;
if (n4 * n5 == 0 || n4 == n5 || n4 == n1 || n4 == n2
|| n4 == n3 || n5 == n1 || n5 == n2 || n5 == n3) {
continue;
}
// 对乘积进行判断
n6 = k / 1000;
n7 = k / 100 % 10;
n8 = k / 10 % 10;
n9 = k % 10;
if ((n3 * n5) % 10 != n9 || n6 * n7 * n8 * n9 == 0
|| n6 == n7 || n6 == n8 || n6 == n9 || n7 == n8
|| n7 == n9 || n8 == n9 || n6 == n1 || n6 == n2
|| n6 == n3 || n6 == n4 || n6 == n5 || n7 == n1
|| n7 == n2 || n7 == n3 || n7 == n4 || n7 == n5
|| n8 == n1 || n8 == n2 || n8 == n3 || n8 == n4
|| n8 == n5 || n9 == n1 || n9 == n2 || n9 == n3
|| n9 == n4 || n9 == n5) {
continue;
}
System.out.println(i + "*" + j + "=" + k);
}
}
}
long t2 = System.nanoTime();// 测试时间的第二个时间点
System.out.println(t2 - t1);
}
}138*42=5796
157*28=4396
159*48=7632
186*39=7254
198*27=5346
297*18=5346
483*12=5796
3038033


2877

被折叠的 条评论
为什么被折叠?



