回溯算法 - Java实现N皇后问题
1.回溯算法
1.1 回溯算法的介绍
-
回溯算法实际上一个类似枚举的深度优先搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回(也就是递归返回),尝试别的路径
-
回溯的处理思想,有点类似枚举(列出所有的情况)搜索。我们枚举所有的解,找到满足期望的解。为了有规律地枚举所有可能的解,避免遗漏和重复,我们把问题求解的过程分为多个阶段。每个阶段,我们都会面对一个岔路口,我们先随意选一条路走,当发现这条路走不通的时候(不符合期望的解),就回退到上一个岔路口,另选一种走法继续走
1.2 N皇后问题的介绍
- n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击
2.Java实现N皇后问题
package com.lagou.backMethod;
/**
* @author 云梦归遥
* @date 2022/5/22 9:49
* @description 回溯算法 - N皇后问题
*/
public class NQueens {
/**
* @param n 表示n * n 的格子
* @param row 当前是多少行
* @param res 用一个数组,记录每一行的皇后所在的列
* @param count 结果总数
* @return
*/
public int nQueen(int n, int row, int[] res, int count) {
if (row == n) {
//打印
print(n, res);
count++;
System.out.println("-----------");
return count;
}
for (int col = 0; col < n; col++) {
//先尝试着把皇后放在这一列
res[row] = col;
//判断和上面行的皇后是否冲突
if (isOk(row, col, res)) {
//迭代,下一行
count = nQueen(n, row + 1, res, count);
}
}
return count;
}
private boolean isOk(int row, int col, int[] res) {
for (int i = 0; i < row; i++) {
//判断上面每行皇后所在列, 如果和当前列相同则为false
if (res[i] == col) {
return false;
}
//判断撇和捺方向, 是两个斜率为1和-1的直线, 则他们两个坐标 |y2 - y1| == |x2 - x1|
if (row - i == col - res[i] || row - i == res[i] - col) {
return false;
}
}
return true;
}
private void print(int n, int[] res) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (res[i] == j) {
System.out.print("Q");
} else {
System.out.print("*");
}
System.out.print(" ");
}
System.out.println();
}
}
}
进行测试
package com.lagou.backMethod.test;
import com.lagou.backMethod.NQueens;
/**
* @author 云梦归遥
* @date 2022/5/22 11:21
* @description
*/
public class NQueensTest {
public static void main(String[] args) {
NQueens nQueens = new NQueens();
int n = 8;
int nQueen = nQueens.nQueen(n, 0, new int[n], 0);
System.out.println("nQueen = " + nQueen);
}
}
3.总结
- 时间复杂度
- N皇后问题的时间复杂度为: O(n ! ),实际为 n ! / 2
- 优缺点
- 优点:
- 回溯算法的思想非常简单,大部分情况下,都是用来解决广义的搜索问题,也就是,从一组可能的解中,选择出一个满足要求的解。回溯算法非常适合用递归来实现,在实现的过程中,剪枝操作是提高回溯效率的一种技巧。利用剪枝,我们并不需要穷举搜索所有的情况,从而提高搜索效率
- 劣势:
- 效率相对于低(动态规划)
- 优点: