前些天有同学去跑社招,面试的时候被人问到8皇后问题,很是杯具。这也说明我们平时对于经典的算法问题关注太少,但设计算法的能力也不是一日之功,需要的是长期的练习和锻炼提高,比如我就很需要锻炼啊,哈哈。
废话不多说,来分析一下问题。
8皇后问题是要在8*8的国际象棋棋盘上放8个皇后,使得任意两个皇后都不能互相吃掉。因为皇后可以吃掉同一行、同一列和同一对角线上的任意棋子,类似于中国象棋的车。求出所有问题解。
这里可以设8个皇后,她们分别在不同的行i(i=1,2,3,4,...,8),而不同的皇后x要在的列,因此解可以有8个点所组成的二维数组。
回溯算法简单来说,就是走不通就掉头再走。这里就简单的使用八重循环进行深度优先搜索,从第一个皇后开始,再找第二个;每找一个就检查是否满足不能被吃掉的约束条件,不满足就continue回溯到上一个皇后,然后继续再尝试下一个。
不被吃掉的条件有三个:
1)不在同一列:xi != xj
2)不在同一对角线:xi - i !=xj - j && xi + i !=xj + j
EightQueens类:
View Code
1 package com.mnid.algorithm;
2 public class EightQueens {
3
4 private int a[] = new int[9];
5
6 public void place() {
7 for (a[1] = 1; a[1] <= 8; a[1] += 1) {
8 for (a[2] = 1; a[2] <= 8; a[2] += 1) {
9 if (check(a, 2))
10 continue;
11 for (a[3] = 1; a[3] <= 8; a[3] += 1) {
12 if (check(a, 3))
13 continue;
14 for (a[4] = 1; a[4] <= 8; a[4] += 1) {
15 if (check(a, 4))
16 continue;
17 for (a[5] = 1; a[5] <= 8; a[5] += 1) {
18 if (check(a, 5))
19 continue;
20 for (a[6] = 1; a[6] <= 8; a[6] += 1) {
21 if (check(a, 6))
22 continue;
23 for (a[7] = 1; a[7] <= 8; a[7] += 1) {
24 if (check(a, 7))
25 continue;
26 for (a[8] = 1; a[8] <= 8; a[8] += 1) {
27 if (check(a, 8))
28 continue;
29 else {
30 for (int i = 1; i <= 8; i++) {
31 System.out.println("(" + i
32 + ", " + a[i] + ")");
33 if (8 == i) {
34 System.out.println("-----------------");
35 }
36 }
37 }
38 }
39 }
40 }
41 }
42 }
43 }
44 }
45 }
46 }
47
48 private boolean check(int[] a, int n) {
49 for (int i = 1; i <= n - 1; i++) {
50 if (Math.abs(a[i] - a[n]) == Math.abs(i - n) || a[i] == a[n]) {
51 return true;
52 }
53 }
54 return false;
55 }
56 }
这个算法缺陷就是只能解决8皇后问题。
对于n皇后问题,以下是采用非递归的深度优先搜索算法实现:
NQueens类:
View Code
1 package com.mnid.algorithm;
2
3 public class NQueens {
4 private int a[] = new int[20];
5
6 public void place(int n) {
7 int k = 1;
8 while (k > 0) {
9 a[k] += 1;
10 while (a[k] <= n && check(k)) { //放第k个皇后
11 a[k] += 1;
12 }
13 if (a[k] <= n) {
14 if (k == n) { //找到一组解
15 print(n);
16 }else {
17 k += 1; //前k个皇后已放好,继续放第k+1个皇后
18 a[k] = 0; //从头开始继续放下一个
19 }
20 } else {
21 k -= 1; //出界则回溯
22 }
23 }
24 }
25
26 private void print(int n) {
27 for (int i=1; i<=n; i++) {
28 System.out.println("(" + i
29 + ", " + a[i] + ")");
30 if (n == i) {
31 System.out.println("-----------------");
32 }
33 }
34 }
35
36 private boolean check(int n) {
37 for (int i = 1; i <= n - 1; i++) {
38 if (Math.abs(a[i] - a[n]) == Math.abs(i - n) || a[i] == a[n]) {
39 return true;
40 }
41 }
42 return false;
43 }
44 }
Placer类:
View Code
1 package com.mnid.algorithm;
2
3 public class Placer {
4 public static void main(String[] args) {
5 new EightQueens().place();
6 // new NQueens().place(8);
7 }
8
9 }