回溯法解n皇后问题
n皇后问题描述是:将n个皇后放在n*n的棋盘上,使得任意两个皇后不在同一行,同一列和同一斜线上,找出解的总数,并输出每个解。(.表示不放皇后,Q表示放置皇后)
我的思路:根据题意可以明显得出,每行/每列有且仅有一个皇后,因此用了point数组的索引表示每个皇后的x坐标,值表示y坐标,并对y坐标进行全排列(x和y均初始化为0-n),对每个排列进行判断是否这个解不在同一斜线即可
Java 代码:
package 回溯;
import java.util.*;
/*
4
2
8
92
*/
/**
* 思路:
* 可以确定每行每列都有且仅有一个皇后,因此行不变,对列进行全排列,并判断各点存在两点是否在一个斜线上
* 判断是否在斜线上:x1 - y1 与 x2 - y2 不同且 x1 + y1 与 x2 + y2 不同,这里用集合处理
*/
public class n后问题 {
public static void main(String[] args) {
new n后问题().solve();
}
// point 索引表示横坐标,值表示纵坐标
int[] point;
char[][] A;
int count = 0;
void solve() {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
point = new int[n];
A = new char[n][n];
init(point);
perm(point);
System.out.println(count);
}
void helper(int[] a, int start, int end) {
if (start == end) {
if (isOk(point)) {
count++;
for (int i = 0; i < end; i++) {
for (int j = 0; j < end; j++) {
A[i][j] = '.';
}
}
for (int i = 0; i < end; i++) A[i][point[i]] = 'Q';
for (int i = 0; i < end; i++) {
for (int j = 0; j < end; j++) {
System.out.print(A[i][j]);
}
System.out.println();
}
System.out.println();
}
return;
}
for (int i = start; i < end; i++) {
swap(a, start, i);
helper(a, start + 1, end);
swap(a, start, i);
}
}
// 全排列
void perm(int[] a) {
helper(a, 0, a.length);
}
void swap(int a[], int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
// 判断一个解是否满足条件:只需判断每个斜线上是否有重复即可
boolean isOk(int[] point) {
int n = point.length;
HashSet<Integer> set1 = new HashSet<>();
HashSet<Integer> set2 = new HashSet<>();
for (int i = 0; i < n; i++) {
if (!set1.contains(i + point[i]) && !set2.contains(i - point[i])) {
set1.add(i + point[i]);
set2.add(i - point[i]);
} else return false;
}
return true;
}
// 初始化
void init(int[] a) {
int n = a.length;
for (int i = 0; i < n; i++) {
a[i] = i;
}
}
}
这里判断是否在同一斜线上的方法:根据一个点(x, y),在同一斜线上的点为
(x - i, y - i)
(x - i, y + i)
(x + i, y - i)
(x + i, y + i)
对于(x1, y1),被判断的点(x2, y2)与它不在同一斜线上的充要条件是:x2 - y2 不等于 x1 - y1 且 x2 + y2 不等于 x1 + y1,代码中用的集合进行判断
输入输出示例:
4
.Q..
...Q
Q...
..Q.
..Q.
Q...
...Q
.Q..
2
提供一些测试例子(仅解的总数),拿去验证:
1 1
2 0
3 0
4 2
5 10
6 4
7 40
8 92
9 352
10 724
11 2680
12 14200
13 73712
14 365596
15 2279184
16 14772512
17 95815104
18 666090624
19 4968057848
20 39029188884
21 314666222712
22 2691008701644
23 24233937684440
24 227514171973736
25 2207893435808352