• 剪枝


    暴力破解的缺点:

    • 循环次数过多
    • 多层循环容易造成分支数爆炸
    • 递归也会引发指数增长

    剪枝:

    • 尽早结束无意义的运算分支
    • 尽量选择分支少的为循环条件
    • 优点: 提高计算速度和效率

    实例分析:

    1.已知要找的总额,和提供的各种面值

    例如:要找8元零钱,可以使用5元,2元,1元和5角组合。

    代码:

    public static void main(String[] args) {
            int sum = 80;
            for (int a = 0; a <= sum / 50; ++a) {
                for (int b = 0; b <= sum / 20; ++b) {
                    for (int c = 0; c <= sum / 10; ++c) {
                        for (int d = 0; d <= sum / 5; ++d) {
                            if (a * 50 + b * 20 + c * 10 + d * 5 == sum) {
                                System.out.println(a + "," + b + "," + c + "," + d);
                            }
                        }
                    }
                }
            }
        }

    这个问题本身不复杂,但是如果将问题复杂化,例如:要找800元零钱,有几十种零钞。循环嵌套的层数就会很深,计算的时间就会非常久。

    剪枝版:

    public static void main(String[] args) {
            int sum = 80;
            for (int a = 0; a <= sum / 50; ++a) {
                for (int b = 0; b <= sum / 20; ++b) {
                    if (80 - 50 * a - 20 * b < 0)  //剪枝
                        break;
                    for (int c = 0; c <= sum / 10; ++c) {
                        int d = (sum - a * 50 - b * 20 - c * 10);
                        if (d < 0)  //剪枝
                            break;
                        d = d / 5; // d直接根据a,b,c的结果计算
                        if (a * 50 + b * 20 + c * 10 + d * 5 == sum) {
                            System.out.println(a + "," + b + "," + c + "," + d);
                        }
    
                    }
                }
            }
        }

    2. n位数的平方的尾数是n位数本身

    代码:

    public static void main(String[] args) {
            for (int i = 100; i < 1000; ++i)
            {
                int n = i * i;  // 3位数的平方    
                int m = n % 1000; // 3位数平方的尾数
                if  (m == i)
                    System.out.println(i+"," + n);
            }
        }

    剪枝版:

    public static void main(String[] args) {
            for (int i = 100; i < 1000; ++i)
            {
                int n = i * i;        // 三位数的平方
                int m = n % 1000; // 3位数平方的尾数
                int geWei = n % 10;  // 三位数平方后的个位
                // 剪枝 过滤
                if (geWei != 0 && geWei != 1 && geWei != 5 && geWei != 6) {
                    continue;
                }
                if  (m == i)
                    System.out.println(i+"," + n);
            }
        }

     3.观察下面的算式:

    △△△ * △△ = △△△△

    某3位数乘以2位数,结果为4位数

    要求:在9个△所代表的数字中,1~9的数字恰好每个出现1次

    代码:

    public static void main(String[] args) {
        {
            long beginTime = System.currentTimeMillis();
            int n1, n2, n3, n4, n5, n6, n7, n8, n9;
            for (int i = 12; i <= 98; ++i) {
                n1 = i / 10;
                n2 = i % 10;
                if (n2 == 0 || n1 == n2)
                    continue;
                for (int j = 123; j <= 987; ++j) {
                    n3 = j / 100;
                    n4 = j / 10 % 10;
                    n5 = j % 10;
                    if (n4 == 0 || n5 == 0)
                        continue;
                    if (n3 == n4 || n3 == n5 || n4 == n5)
                        continue;
                    if (n3 == n1 || n3 == n2 || n4 == n1 || n4 == n2 || n5 == n1
                            || n5 == n2)
                        continue;
    
                    int k = i * j;
                    if (k < 1234 || k > 9876)
                        continue;
    
                    n6 = k / 1000;
                    n7 = k / 100 % 10;
                    n8 = k / 10 % 10;
                    n9 = k % 10;
                    if (n7 == 0 || n8 == 0 || n9 == 0)
                        continue;
                    if (n6 == n7 || n6 == n8 || n6 == n9 || n7 == n8 || n7 == n9
                            || n8 == n9)
                        continue;
                    if (n6 == n1 || n6 == n2 || n6 == n3 || n6 == n4 || n6 == n5)
                        continue;
                    if (n7 == n1 || n7 == n2 || n7 == n3 || n7 == n4 || n7 == n5)
                        continue;
                    if (n8 == n1 || n8 == n2 || n8 == n3 || n8 == n4 || n8 == n5)
                        continue;
                    if (n9 == n1 || n9 == n2 || n9 == n3 || n9 == n4 || n9 == n5)
                        continue;
    
                    System.out.println(j + "," + i + "," + k);
    
                }
            }
    
            long endTime = System.currentTimeMillis();
            System.out.println("用时: " + (endTime - beginTime) + " ms");
        }
    View Code

    效果:

    使用HashSet

    public static void main(String[] args) {
            Set<Integer> set = new HashSet<Integer>();
            int n1, n2, n3, n4, n5, n6, n7, n8, n9;
            long beginTime = System.currentTimeMillis();
    
            for (int i = 123; i <= 987; ++i) {
                set.clear();
                n1 = i / 100;
                n2 = i / 10 % 10;
                n3 = i % 10;
                if (n2 == 0 || n3 == 0) // 不能为0
                    continue;
                if (n1 == n2 || n1 == n3 || n2 == n3) // 不能重复
                    continue;
    
                set.add(n1);
                set.add(n2);
                set.add(n3);
    
                for (int j = 12; j <= 98; ++j) {
                    n4 = j / 10;
                    n5 = j % 10;
                    if (n5 == 0)
                        continue;
                    if (n4 == n5)
                        continue;
                    if (set.contains(n4) || set.contains(n5))
                        continue;
    
                    int k = i * j;
                    if (k < 1234 || k > 9876)
                        continue;
    
                    n6 = k / 1000;
                    n7 = k / 100 % 10;
                    n8 = k / 10 % 10;
                    n9 = k % 10;
    
                    if (n6 == 0 || n7 == 0 || n8 == 0 || n9 == 0) {
                        continue;
                    }
                    if (n6 == n7 || n6 == n8 || n6 == n9 || n7 == n8 || n7 == n9
                            || n8 == n9) {
                        continue;
                    }
                    set.add(n4);
                    set.add(n5);
    
                    if (set.contains(n6) || set.contains(n7) || set.contains(n8)
                            || set.contains(n9)) {
                        set.remove(n4);
                        set.remove(n5);
                        continue;
                    }
    
                    System.out.println(i + "," + j + "," + k);
    
                    set.remove(n4);
                    set.remove(n5);
                }
    
            }
            long endTime = System.currentTimeMillis();
            System.out.println("总计用时:" + (endTime - beginTime) + "ms");
    
        }
    View Code

    效果:

  • 相关阅读:
    Ubuntu忘记密码后强制修改密码
    搭建Jetbrains家族IDE授权服务器
    C#ComboBox绑定List
    字体包文件过大
    JS通过ActiveX读写ini配置文件
    NodeJS + express访问html、css、JS等静态资源文件
    VueJS搭建简单后台管理系统框架 (二) 模拟Ajax数据请求
    VueJS搭建简单后台管理系统框架(一)环境搭建
    ExtJS4.x Grid 单元格鼠标悬停提示
    IE9下Ajax缓存问题
  • 原文地址:https://www.cnblogs.com/hupeng1234/p/6818857.html
Copyright © 2020-2023  润新知