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

来源:互联网 发布:哪里有淘宝美工培训班 编辑:程序博客网 时间:2024/05/05 07:23

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,62576,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,01,15,256,3625,62576,5776376,141376625,3906259376,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 5796157 28 4396159 48 7632186 39 7254198 27 5346297 18 5346483 12 57968017慢的一逼



改进一下:

/*观察下面的算式:△△△ * △△ = △△△△某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=5796157*28=4396159*48=7632186*39=7254198*27=5346297*18=5346483*12=57963043679



改进版
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=5796157*28=4396159*48=7632186*39=7254198*27=5346297*18=5346483*12=57963038033


1 0
原创粉丝点击