编程算法基础-枚举与剪枝

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


评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值