八皇后
八皇后
八皇后问题的描述一般是这样的:每个皇后能够攻击他所在的行、列、以及斜边,在n*n的棋盘上如何放置n个皇后让他们不相互攻击?
在解决这个问题之前我们要先了解两个东西:
- 如何实现排列(这个可以看我之前写的如何实现排列和组合)
- 如何解决斜边的标记问题
关于行和列的标记就不多说废话了.直接来看如何实现斜边的标记
| 5 | (5,1) | (5,2) | (5,3) | (5,4) | (5,5) |
| 4 | (4,1) | (4,2) | (4,3) | (4,4) | (4,5) |
| 3 | (3,1) | (3,2) | (3,3) | (3,4) | (3,5) |
| 2 | (2,1) | (2,2) | (2,3) | (2,4) | (2,5) |
| 1 | (1,1) | (1,2) | (1,3) | (1,4) | (1,5) |
- | 1 | 2 | 3 | 4 | 5
我们直接来看这个数组,姑且先把斜边分为与主对角线平行的和与副对角线平行的两类.
-
先来观察与主对角线平行的斜边,会发现这条斜边上的每个点的行+列的值是相同的.
如5+1=6 4+2=6 3+3=6 .... -
再来观察与副对角线平行的斜边,会发现这条斜边上的每个点的行-列的值是相同的.
如5-5=0 4-4=0 3-3=0 ....
了解了这个之后就好解决问题了.利用这个性质可以对排列进行剪枝(或者说回溯?)
直接上代码
import java.util.LinkedList;
import java.util.Scanner;
public class DFS03 {
static int count = 0;// 符合条件的个数
static int n;// 棋盘大小n*n
static LinkedList<Integer> place = new LinkedList<>();
// 皇后出现的位置
static boolean[] flag1 = new boolean[50], flag2 = new boolean[50], flag3 = new boolean[50];
// 皇后能够影响的列,主对角线,和副对角线
// 使用的数组声明大一些,防止出现数组越界
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
dfs(1);
System.out.println(count);
}
static void dfs(int h) {
if (h > n) {
System.out.println(place);
count++;
return;
}
for (int i = 1; i <= n; i++) {
if (!flag1[i] && !flag2[h + i] && !flag3[h - i + n]) {
//如果都i对应的列和主对角线和副对角线都没有被影响到
place.add(i);
flag1[i] = true;//标记
flag2[h + i] = true;//标记
flag3[h - i + n] = true;//标记
dfs(h + 1);
place.removeLast();
flag1[i] = false;//取消标记
flag2[h + i] = false;//取消标记
flag3[h - i + n] = false;//取消标记
}
}
}
}
-
关于标记副对角线还需要加一个偏置值,因为副对角线的行-列的值会出现负值.不加偏置值会造成索引为负的情况.
-
不要说为什么代码没有去标记行,本身第一个数就是代表第一行,第二个数代表第二行.....当然不需要标记啦.

浙公网安备 33010602011771号