Java实现N皇后问题的双路径探索:递归回溯与迭代回溯算法详解

N皇后问题要求在N×N的棋盘上放置N个皇后,使得她们无法互相攻击。本文提供递归和循环迭代两种解法,并通过图示解释核心逻辑。


一、算法核心思想

使用回溯法逐行放置皇后,通过冲突检测保证每行、每列、对角线上只有一个皇后。发现无效路径时回退到上一状态。

冲突检测条件(关键):
  1. 同列冲突:col[i] == col[j]
  2. 对角线冲突:abs(col[i] - col[j]) == abs(i - j)

二、递归版本实现

  1. 流程图

  1. 时序图

  1. 代码解释

  1. 程序目的
    该代码用于解决N皇后问题,即在N×N棋盘上放置N个皇后,使其互不攻击(即任意两个皇后不在同一行、列或对角线上),返回所有可能的解。
  2. solveNQueens方法
    • 初始化结果列表result,用于存储所有解。
    • 调用backtrack方法启动递归回溯过程。
    • 参数n表示棋盘大小,cols数组记录每行皇后所在的列位置(索引为行,值为列)。
  3. backtrack递归核心
    • 终止条件:当row == n时,表示所有皇后已正确放置,将当前cols数组的拷贝加入结果(避免后续修改影响结果)。
    • 递归逻辑:遍历当前行的每一列col,若位置有效则放置皇后(cols[row] = col),并递归处理下一行(row + 1)。
  4. isValid冲突检查
    • 检查当前列col与之前所有行(0row-1)的皇后是否冲突:
      • 列冲突cols[i] == col,即同一列已有皇后。
      • 对角线冲突Math.abs(col - cols[i]) == row - i,即行差等于列差绝对值。
    • 若任一条件满足,返回false,否则位置有效。
  5. 主函数测试与输出
    • 测试n=4的皇后问题,调用solveNQueens获取所有解。
    • 使用Lambda表达式遍历打印每个解(如[1, 3, 0, 2]表示第0行皇后在1列,第1行在3列等)。
  6. 关键实现细节
    • 回溯剪枝:仅尝试有效位置,减少递归次数。
    • 结果存储:每次成功时创建新的ArrayList保存当前解,避免引用问题。
    • 递归层次:每层递归处理一行皇后,确保每行只有一个皇后。

示例输出:
对于n=4,输出两个解:[1, 3, 0, 2][2, 0, 3, 1],对应两种不同的棋盘布局方式。

  1. 代码实现
    1. 注意:下标从0开始
import java.util.ArrayList;
import java.util.List;public class NQueensRecursive {public static List<List<Integer>> solveNQueens(int n) {List<List<Integer>> result = new ArrayList<>();backtrack(n, 0, new Integer[n], result);return result;}private static void backtrack(int n, int row, Integer[] cols, List<List<Integer>> result) {if (row == n) {result.add(new ArrayList<>(List.of(cols)));return;}for (int col = 0; col < n; col++) {if (isValid(cols, row, col)) {cols[row] = col;backtrack(n, row + 1, cols, result);}}}private static boolean isValid(Integer[] cols, int row, int col) {for (int i = 0; i < row; i++) {if (cols[i] == col || Math.abs(col - cols[i]) == row - i) {return false;}}return true;}public static void main(String[] args) {List<List<Integer>> solutions = solveNQueens(4);solutions.forEach(System.out::println);}
}


三、循环迭代版本实现

  1. 时序图

  1. 流程说明
  1. 初始化阶段
    • 清空皇后位置数组
    • 从第一个皇后开始放置(j=1)
  2. 主循环逻辑
    • 每次循环尝试将当前皇后的位置右移一格
    • 通过check()验证当前位置是否:
      • 与已有皇后同列
      • 处于同一斜线
    • 合法时继续处理下一个皇后,非法时继续右移
    • 当完成最后一列放置时输出有效方案
  3. 回溯机制
    • 当某列所有位置尝试失败后
    • 重置当前列位置为0
    • 回溯到前一列继续尝试新位置
  4. 终止条件
    • 当回溯到j=0时说明所有可能性已穷尽
    • 程序正常结束

该实现通过非递归方式实现了经典的回溯算法,使用while循环和位置重置机制替代了递归调用栈,具有较好的空间效率。

  1. 代码实现
    1. 注意:下标从1开始
public class Test {// 定义4个皇后static final  Integer N = 4;// 存储皇后的列号static int[] q =  new int[N+1];// 方案数static int answer =0;public static void main(String[] args) {queen();}public static boolean check(int j){for(int i=1;i<j;i++){if(q[i]==q[j] || Math.abs(i-j)==Math.abs(q[i]-q[j])){ // 判断是否同列或同一斜线return false;}}return true;}public static void queen(){queenInit();int j = 1; // 表示正在摆放第j个皇后while(j>=1){q[j] ++;// 让第j个皇后的位置加1while(!check(j) && q[j]<=N){ // 不满足条件的话,就一直向后移动,为了防止越界,还需要判断q[j]的长度q[j]++;}// 判断if(q[j]<=N){// 表示第j个位置,合法if(j==N){// 最后一个皇后已经摆放完毕了answer++;System.out.print("方案"+answer);System.out.print("结果为:");for (int i = 1; i <=N ; i++) {System.out.print(q[i]+",");}System.out.println();}else{// 继续找下一个皇后的摆放位置j++;}}else{// 没有位置摆放了,需要回溯到上一次。q[j]=0; // 重置位置j--;}}}// 皇后初始化public static void queenInit(){for(int i=1;i<=N;i++){q[i]=0;}}
}


四、算法流程图示(以4皇后为例)

步骤分解:
1. 放置行0的皇后在列0Q . . .. . . .. . . .. . . .2. 行1尝试列0(冲突)→ 尝试列1(冲突)→ 列2有效Q . . .. . Q .. . . .. . . .3. 行2尝试所有列均冲突,回溯到行1Q . . .. . . . ← 行1无法继续. . . .. . . .4. 行1移动到列3Q . . .. . . Q. . . .. . . .5. 行2尝试列1有效Q . . .. . . Q. Q . .. . . .6. 行3无有效列,回溯→最终找到解:[1, 3, 0, 2] 对应棋盘:. Q . .. . . QQ . . .. . Q .

五、算法对比

特性递归版本循环迭代版本
代码复杂度简洁,易理解需手动管理状态栈
内存消耗有栈深度限制显式栈结构,可控性强
适用场景小规模数据,代码可读性优先避免栈溢出,大数据量更稳定

两种方法时间复杂度均为O(N!),实际效率相近,选择依据具体场景需求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/75665.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端判断值相等的方法和区别

1. (宽松相等) 在比较之前会进行类型转换 可能导致一些意外的结果 0 // true 0 0 // true false 0 // true null undefined // true [1,2,3]1,2,3 // true2. (严格相等) 不进行类型转换 类型和值都必须相同 0 // false 0 0 // false false 0 /…

Socket编程UDP

Socket编程UDP 1、V1版本——EchoServer2、网络命令2.1、ping2.2、netstat2.3、pidof 3、验证UDP——Windows作为client访问Linux4、V2版本——DictServer5、V3版本——简单聊天室 1、V1版本——EchoServer 首先给出EchoServer目录结构&#xff1a;服务器的类我们实现在UdpServ…

辅助查询是根据查询到的文档片段再去生成新的查询问题

&#x1f4a1; 辅助查询是怎么来的&#xff1f; 它是基于你当前查询&#xff08;query&#xff09;检索到的某个文档片段&#xff08;chunk_result&#xff09;&#xff0c;再去“反推”出新的相关问题&#xff08;utility queries&#xff09;&#xff0c;这些问题的作用是&a…

2025 年 4 月补丁星期二预测:微软将推出更多 AI 安全功能

微软正在继续构建其 AI 网络安全战略&#xff0c;并于本月宣布在 Microsoft Security Copilot 中引入新代理。 他们引入了用于网络钓鱼分类的代理、用于数据丢失预防和内部风险管理的警报分类、条件访问优化、漏洞修复和威胁情报简报。 这些代理的目标是不断从这些不同学科中…

【LLM系列】1.大模型简介

1. 基础 1.1 如何权衡模型的复杂度和性能&#xff1f; ├── a. 模型架构选择 │ ├── 简化架构 │ │ └── 选择较小的网络层数和宽度&#xff0c;降低复杂度&#xff1b; │ │ 可使用高性能基础模型如 Transformers 作为起点&#xff0c;根据需求缩放模型。 │ └──…

【leetcode】记录与查找:哈希表的题型分析

前言 &#x1f31f;&#x1f31f;本期讲解关于力扣的几篇题解的详细介绍~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那么废话不…

优选算法的妙思之流:分治——快排专题

专栏&#xff1a;算法的魔法世界 个人主页&#xff1a;手握风云 目录 一、快速排序 二、例题讲解 2.1. 颜色分类 2.2. 排序数组 2.3. 数组中的第K个最大元素 2.4. 库存管理 III 一、快速排序 分治&#xff0c;简单理解为“分而治之”&#xff0c;将一个大问题划分为若干个…

二叉树的ACM板子(自用)

package 二叉树的中序遍历;import java.util.*;// 定义二叉树节点 class TreeNode {int val; // 节点值TreeNode left; // 左子节点TreeNode right; // 右子节点// 构造函数TreeNode(int x) {val x;} }public class DMain {// 构建二叉树&#xff08;层序遍历方式&…

Linux常用命令详解:从基础到进阶

目录 一、引言 二、文件处理相关命令 &#xff08;一&#xff09;grep指令 &#xff08;二&#xff09;zip/unzip指令 ​编辑 &#xff08;三&#xff09;tar指令 &#xff08;四&#xff09;find指令 三、系统管理相关命令 &#xff08;一&#xff09;shutdown指…

Qt多线程从基础到性能优化

一、为什么需要多线程开发 现代应用程序的性能需求 CPU多核架构的有效利用 复杂任务的解耦与响应式界面保持 二、Qt线程创建四大方式 1. 继承QThread重写run() class WorkerThread : public QThread {void run() override {// 耗时操作qDebug() << "Thread ID…

【java】在 Java 中,获取一个类的`Class`对象有多种方式

在 Java 中&#xff0c;获取一个类的Class对象有多种方式。Class对象代表了 Java 中的一个类或接口的运行时类信息&#xff0c;可以用于反射操作。以下是获取Class对象的几种常见方法&#xff1a; 1.使用.class属性 每个类都有一个.class属性&#xff0c;可以直接获取该类的Cl…

什么是RPC通信

RPC&#xff08;Remote Procedure Call&#xff0c;远程过程调用&#xff09;通信是一种允许程序像调用本地函数一样调用远程服务器上函数的通信技术。它简化了分布式系统中的网络交互&#xff0c;隐藏了底层网络通信的复杂性&#xff0c;使开发者能够专注于业务逻辑。 一、RPC…

还是主题混合程序设计

以下是针对您现有代码的完整主题化改造方案&#xff0c;实现跨QML/Qt Widgets的阴影主题系统&#xff1a; 一、主题管理系统核心 // thememanager.h #pragma once #include <QObject> #include <QColor> #include <QMap> #include <QQmlEngine>class…

BT-Basic函数之首字母T

BT-Basic函数之首字母T 文章目录 BT-Basic函数之首字母Ttabtesttest conttest monitortest on boardstest scanworkstest shortstesthead cleanuptesthead configurationtesthead istesthead power on/offtesthead statustestjet print level istestordertestplan generationth…

7-9 趣味游戏

题目解析 在某个学校的趣味游戏活动中&#xff0c;N 名同学站成一排&#xff0c;他们的年龄恰好是 1 到 N &#xff0c;需要注意的是他们并不是按照年龄的大小排列的&#xff0c;而是随机排列的。 游戏的规则是请同学们快速计算出&#xff0c;如果在这 N 名同学的小组中&…

Hugging Face模型微调训练(基于BERT的中文评价情感分析)

文章目录 学习视频地址项目地址数据集的下载模型微调的基本概念与流程加载数据集数据集格式数据集信息 制作Dataset数据集字段数据集信息 vocab字典操作词汇表文本转换 下游任务模型设计模型训练与保存数据加载优化器训练循环 最终效果评估与测试模型加载和测试 学习视频地址 …

【蓝桥杯】十五届省赛B组c++

目录 前言 握手问题 分析 排列组合写法 枚举 小球反弹 分析 代码 好数 分析 代码 R 格式 分析 代码 宝石组合 分析 代码 数字接龙 分析 代码 拔河 分析 代码 总结 前言 主播这两天做了一套蓝桥杯的省赛题目&#xff08;切实感受到了自己有多菜&#x…

必刷算法100题之计算右侧小于当前元素的个数

题目链接 315. 计算右侧小于当前元素的 个数 - 力扣&#xff08;LeetCode&#xff09; 题目解析 计算数组里面所有元素右侧比它小的数的个数, 并且组成一个数组,进行返回 算法原理 归并解法(分治) 当前元素的后面, 有多少个比我小(降序) 我们要找到第一比左边小的元素, 这…

Hyperlane框架:下一代高性能Rust Web框架 [特殊字符]

Hyperlane框架&#xff1a;下一代高性能Rust Web框架 &#x1f680; 引言 &#x1f44b; 在当今快速发展的Web开发领域&#xff0c;性能和开发效率的平衡变得越来越重要。Hyperlane作为一个新兴的Rust Web框架&#xff0c;完美地解决了这个问题。本文将带您深入了解Hyperlane…

图像处理:使用Numpy和OpenCV实现傅里叶和逆傅里叶变换

文章目录 1、什么是傅里叶变换及其基础理论 1.1 傅里叶变换 1.2 基础理论 2. Numpy 实现傅里叶和逆傅里叶变换 2.1 Numpy 实现傅里叶变换 2.2 实现逆傅里叶变换 2.3 高通滤波示例 3. OpenCV 实现傅里叶变换和逆傅里叶变换及低通滤波示例 3.1 OpenCV 实现傅里叶变换 3.2 实现逆傅…