1、八皇后问题
在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
穷举法:将所有皇后的所有可能位置都摆放好,然后对每一种摆放位置进行判断,类似于全排列,时间复杂度是O(1),但如果是n皇后,时间复杂度就是O(nⁿ),这个复杂度是不能接受的。
经典的回溯算法问题:选择第一个皇后摆放好,判断是否可以互相攻击到,如果不能则摆放下一个皇后,再次判断,如果可以互相攻击则进行回溯,把这个皇后摆放到下一个位置,····,八个皇后摆放完成,解法+1,回溯,寻找下一种解法。
八皇后问题简单来说就两个动作:摆放棋子、判断是否会被攻击 ? (当前皇后还有位置可摆 ? 继续循环 : 回溯) : 摆放下一个棋子 ;
并且每个皇后都是独立的,不同的个体。
代码如下:
/**
* 这里我们会使用一维数组代替二维数组
* 皇后摆放位置要求不能在同一行,我们使用一维数组的下标代表皇后所在列即可,这样皇后就不在同一列了
* @author lxh
* @date 2020-09-03 14:35
*/
public class EightQueenProblem {
//使用一个长度为8的数组解决,下标即为皇后所在列, 数组元素即为皇后所在行
int[] queen = new int[ 8 ];
int count = 0;
public static void main(String[] args) {
EightQueenProblem eightQueenProblem = new EightQueenProblem();
// 0 代表 第一个皇后 ··· 7代表第8个皇后
eightQueenProblem.placeQueen(0);
// 八皇后问题有 92 种解法
System.out.println(eightQueenProblem.count);
}
/**
* 放置棋子的方法
* @param n 第n个皇后
*/
public void placeQueen(int n) {
//如果n==8,说明0~7个皇后都放置好了,即一种解法找到了
if (n == 8) {
count++;
// 找到了其中一种解法,位置摆放在queen数组中,可以做其他操作
} else {
for (int i = 0; i < queen.length; i++) {
// 将第n个皇后放置在 i,n 位置上,回溯也是这里开始的,如果n已经没有合适的位置了,那么会回溯到n-1的地方开始,找到n-1这个皇后可以放置的位置,再次递归到n,判断n可以放置的位置
queen[ n ] = i;
// 判断这个皇后的位置是否合理,如果合理则开始放下一个皇后,或者说在下一列放置棋子
if (testAttack(n)) {
placeQueen(n + 1);
}
}
}
}
/**
* 判断当前棋子与放置好的棋子有没有冲突
* @param n 第n个皇后,也代表第n列
* @return
*/
public boolean testAttack(int n) {
for (int i = 0; i < n; i++) {
//如果棋子在同一行上或者在同一斜线上则返回false
if (queen[ i ] == queen[ n ] || Math.abs(n - i) == Math.abs(queen[ i ] - queen[ n ])) {
return false;
}
}
return true;
}
}
2、由8皇后问题衍生的n皇后问题:LeetCode第51题(困难)
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
提示:
- 皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一条横行、纵行或斜线上。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
这里只需要将8皇后的代码修改一下即可
class Solution {
int[] queens;
List<List<String>> ans=new ArrayList<>();
public List<List<String>> solveNQueens(int n) {
queens=new int[n];
placeQueen(0);
return ans;
}
/**
* 放置棋子的方法
*/
public void placeQueen(int n){
if(n==queens.length){
addRes();
}else{
for(int i=0;i<queens.length;i++){
queens[n]=i;
if(testAttack(n)){
placeQueen(n+1);
}
}
}
}
/**
* 得到解法后的处理
*/
public void addRes(){
List<String> list=new ArrayList<>();
char[] chs=new char[queens.length];
for(int i=0;i<queens.length;i++){
chs[i]='.';
}
for(int i=0;i<queens.length;i++){
chs[queens[i]]='Q';
list.add(new String(chs));
chs[queens[i]]='.';
}
ans.add(list);
}
/**
* 判断当前棋子与放置好的棋子有没有冲突
*/
public boolean testAttack(int n){
for(int i=0;i<n;i++){
if(queens[n]==queens[i] || Math.abs(i-n)==Math.abs(queens[i]-queens[n])){
return false;
}
}
return true;
}
}