全排列问题

简介: 全排列问题

问题提出:


fa0bed3248534e7f9297a976edc247cf_5673298fecb04b128cf2499dac670951.png


上述问题就是典型的全排列问题!!


一、回溯法


回溯:就是类似枚举的搜索尝试过程。在搜索过程中寻找问题的解。当发现不满足求解的条件时,就回溯返回,尝试别的路径。


全排列可以使用试探的方法列举所有的可能性。一个长度为n的序列,所有排列组合:n!


1.从集合中选取一个元素(n种情况),并标记该元素已被使用

2. 在第一步的基础上递归到下一层,从剩余的n-1个元素中,按照第一步的方法找到一个元素,并标记(n-1)

3. 以此类推,所有元素都被标记,将元素存起来,去对比求解的情况

在解题前我们先给定数组在三角形上的对应下标:


07190e673b756d2c95eb5df0a66a22f0_dce0137513274f2d8d343e84216f5218.png


代码实现:


public class 全排列_回溯法 {
    static int count = 0;// 记录总个数
    static boolean[] bool = new boolean[10];
    static int[] arr = new int[10];// 存放数据
    public static void main(String[] args) {
        dfs(1);
        System.out.println(count / 6);//144
    }
    public static void dfs(int step) {
        // 结束条件
        if (step == 10) {
            if (arr[1] + arr[2] + arr[3] + arr[4] == arr[4] + arr[5] + arr[6] + arr[7]
                    && arr[1] + arr[2] + arr[3] + arr[4] == arr[7] + arr[8] + arr[9] + arr[1]) {
                count++;
            }
            return;
        }
        for (int i = 1; i < 10; i++) {
            // 判断i位置上是否放置了数字
            if (!bool[i]) {
                arr[step] = i;
                bool[i] = true;
                dfs(step + 1);
                bool[i] = false;
            }
        }
    }
}


二、邻里交换法


邻里交换法:


回溯是试探性填充数据,给每个位置都试探性赋值

邻里交换,也是通过递归实现,但是是一种基于交换的思路

步骤:


1.将数组分为2个部分,暂时确定部分和未确定部分,刚开始都是未确定部分在未确定的部分中,让每一个数据都有机会和未确定部分中的第一位交换,然后第一位就变成暂时确定部分。

2. 以此类推:每个数据都和未确定部分中的第二位交换(第一位数据除外)...直到确定所有数据。

3. 将确定好的数据和条件对比,对比结束后,还原数据。

代码实现:


public class 全排列_邻里交换法 {
    static int count = 0;
    static int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    public static void main(String[] args) {
        f(arr, 0);
        System.out.println(count / 6);//144
    }
    public static void f(int arr[], int step) {
        if (step == arr.length - 1) {
            if (arr[0] + arr[1] + arr[2] + arr[3] == arr[3] + arr[4] + arr[5] + arr[6]
                    && arr[0] + arr[1] + arr[2] + arr[3] == arr[6] + arr[7] + arr[8] + arr[0]) {
                count++;
            }
            return;
        }
        for (int i = step; i < arr.length; i++) {
            // 交换
            {
                int temp = arr[i];
                arr[i] = arr[step];
                arr[step] = temp;
            }
            f(arr, step + 1);
            // 还原数据
            {
                int temp = arr[i];
                arr[i] = arr[step];
                arr[step] = temp;
            }
        }
    }
}


三、暴力解法


public class 全排列_暴力解法 {
    static int count = 0;
    public static void main(String[] args) {
        for (int a = 1; a <= 9; a++) {// 1
            for (int b = 1; b <= 9; b++) {// 2
                for (int c = 1; c <= 9; c++) {// 3
                    for (int d = 1; d <= 9; d++) {// 4
                        for (int e = 1; e <= 9; e++) {// 5
                            for (int f = 1; f <= 9; f++) {// 6
                                for (int g = 1; g <= 9; g++) {// 7
                                    for (int h = 1; h <= 9; h++) {// 8
                                        for (int i = 1; i <= 9; i++) {// 9
                                            // 不能重复
                                            if (a == b || a == c || a == d || a == e || a == f || a == g || a == h
                                                    || a == i || b == c || b == d || b == e || b == f || b == g
                                                    || b == h || b == i || c == d || c == e || c == f || c == g
                                                    || c == h || c == i || d == e || d == f || d == g || d == h
                                                    || d == i || e == f || e == g || e == h || e == i || f == g
                                                    || f == h || f == i || g == h || g == i || h == i) {
                                                continue;
                                            }
                                            if (a + b + c + d == d + e + f + g && a + b + c + d == g + h + i + a) {
                                                count++;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        System.out.println(count / 6);//144
    }
}
目录
相关文章
|
JavaScript 搜索推荐 前端开发
Vue的SSR 是什么,优缺点分析
Vue的服务器端渲染(SSR)是一种将Vue组件在服务器上执行,并生成完整的HTML页面的技术,这个HTML页面随后被发送至客户端的浏览器进行展示。
|
Web App开发 网络协议 安全
|
11月前
|
安全 数据安全/隐私保护
阿里云企业邮箱怎么开始双重认证具体步骤
要开启阿里云企业邮箱的双重认证,需登录管理员账号,导航至安全管理设置,进入密码策略,点击“开启阿里邮箱双重认证”。开启后,用户需通过手机验证码或安全问题进行二次验证。注意:此功能仅支持网页邮箱和官方客户端,且影响所有用户。
637 5
|
11月前
|
开发者 UED 容器
鸿蒙next版开发:ArkTS组件通用属性(Flex布局)
在HarmonyOS next中,ArkTS的Flex布局是一种强大且灵活的布局方式,支持水平或垂直方向排列元素,并能动态调整大小和位置以适应不同屏幕。主要属性包括justifyContent、alignItems、direction和wrap,适用于导航栏、侧边栏和表单等多种场景。示例代码展示了如何使用这些属性创建美观的布局。
425 10
|
11月前
|
UED 开发者
鸿蒙next版开发:ArkTS组件通用属性(边框设置)
在HarmonyOS 5.0中,ArkTS提供了丰富的边框设置属性,允许开发者自定义组件的边框样式,提升应用的视觉效果和用户体验。本文详细解读了border属性的使用方法,并提供了示例代码,展示了如何设置不同边的边框宽度、颜色、圆角和样式。边框设置在UI开发中具有重要作用,如区分组件、强调重要元素和美化界面。
1037 6
ly~
|
12月前
|
Ubuntu Linux C语言
SDL 图形库安装常见错误及解决方法
SDL(Simple DirectMedia Layer)图形库安装过程中可能会遇到编译错误、运行时错误、依赖库缺失等问题。本文总结了在 Linux 和 Windows 系统上常见的错误及解决方法,包括检查和安装依赖库、配置 SDL 子系统、处理 X11 错误等,帮助用户顺利完成 SDL 的安装和配置。
ly~
2103 8
|
关系型数据库 Java MySQL
Linux安装JDK1.8 & tomcat & MariaDB(MySQL删减版)
本教程提供了在Linux环境下安装JDK1.8、Tomcat和MariaDB的详细步骤。这三个组件的组合为Java Web开发和部署提供了一个强大的基础。通过遵循这些简单的指导步骤,您可以轻松建立起一个稳定、高效的开发和部署环境。希望这个指导对您的开发工作有所帮助。
413 8
|
缓存 Java
JDK序列化原理问题之Fury如何实现与JDK序列化100%兼容的如何解决
JDK序列化原理问题之Fury如何实现与JDK序列化100%兼容的如何解决
216 0
|
XML JSON 前端开发
深入对比TOML,JSON和YAML
坦率地说,在我开始与Hugo TOML合作之前,我感到羞耻是一个需要发现的新领域,但我对YAML和JSON非常熟悉。本文将帮助您了解如何通过不同的数据格式构建数据。       在Hugo中,您可以将所有这三种数据格式用于配置,前置事项和自定义数据,但TOML是用于整个项目的推荐格式。
10238 179
|
JSON JavaScript 前端开发
如何通过 JavaScript 运行用 Go 编写的 WebAssembly 模块? 下
如何通过 JavaScript 运行用 Go 编写的 WebAssembly 模块?
345 0