8皇后問題
最近在學習數據結構中的遞歸算法,並且使用遞歸思想學習了著名的8皇后問題。
-
先談談自己對遞歸的理解吧。遞歸算法就是程序不斷的調用自身的過程,遞歸的過程中,一定要注意兩點:1.一定要有終止遞歸的條件;2.一定要不斷的逼近遞歸的終止條件。程序每次調用自身,就會在調用處重新開闢一個棧空間,如果調用的參數是基本數據類型,那麼這個棧空間會將參數作爲局部變量存放,只供當前棧空間使用。如果調用的參數是引用數據類型,那麼會將該參數存放在堆空間中成爲成員變量供整個程序使用。當達到遞歸終止條件時,會將結果返回給上一次遞歸的位置,直至返回給第一次遞歸的位置,然後繼續代碼繼續向下執行。
-
8皇后問題的規則是:在一個8*8大小的棋盤上,每行放置一個皇后,一共放置8個皇后,這8個皇后之間要保證:1.不在同一列;2.不在同一斜線、反斜線上。問共有多少種擺法?
-
8皇后問題的解決思路:
1.將第一個皇后放在第一行第一列上;
2.之後將每個皇后從下一行的第一列開始放置,然後判斷是否與之前的皇后有衝突;
3.如果有衝突,就放在下一列上,繼續判斷;
4.如果當前皇后在8列上都與之前的皇后有衝突,就將上一個皇后往所處行的下一列放置(回溯);
5.反覆執行2-4步,直至開始放置第9個皇后時,終止遞歸,跳出方法; -
8皇后問題的第一種解決方式是定義一個88的二維數組模擬棋盤,規定88棋盤沒有放置皇后的位置全部爲0,放置皇后的位置全部爲1。
package com.recursion;
/*
* 使用二維數組實現8皇后問題
* 默認棋盤初始化全爲0,每放一個皇后,該位置置爲1
*/
public class Queen8Demo3 {
// 表示8*8棋盤
static int[][] array = new int[8][8];
// 計數
static int count = 0;
public static void main(String[] args) {
put(0);
System.out.printf("一共有%d種解法\n", count);
}
// 擺放皇后
public static void put(int n) {
if (n == 8) {
System.out.println("第" + count + "種解法");
print();
return;
}
for (int i = 0; i < 8; i++) {
//每次將當前行上的皇后清空
for (int j = 0; j < 8; j++) {
array[n][j] = 0;
}
// 如果不衝突
if (judge(n, i)) {
// 每次先將第n個皇后放在第n行的第一列
array[n][i] = 1;
put(n + 1);
}
}
}
// 每次放一個皇后,就判斷是否與之前的皇后在同一列或者同一斜線
public static boolean judge(int n, int y) {
// 判斷是否在同一列上
for (int i = n; i >= 0; i--) {
if (array[i][y] == 1) {
return false;
}
}
// 判斷從右上到左下的斜線方向
for (int i = n, j = y; i >= 0 && j >= 0; i--, j--) {
if (array[i][j] == 1) {
return false;
}
}
// 判斷左上到右下的斜線方向
for (int i = n, j = y; i >= 0 && j < array.length; i--, j++) {
if (array[i][j] == 1) {
return false;
}
}
return true;
}
// 打印棋盤
public static void print() {
count++;
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
System.out.print(array[i][j] + " ");
}
System.out.println();
}
}
}
- 8皇后問題的第二種解決方式是通過創建一個長度爲8的一維數組,該數組的下標表示棋盤的第幾行,也代表第幾個皇后,數組中每個位置上的具體數組表示皇后放在該行的第幾列
package com.recursion;
/*
* 8皇后問題,用一維數組實現,下標表示第幾行,也就是第幾個皇后,值代表第幾列
*/
public class Queen8Demo2 {
//創建一個長度爲8的數組,用來存放皇后的位置
static int[] array=new int[8];
//計數
static int count=0;
public static void main(String[] args) {
put(0);
System.out.printf("共有%d種擺法\n",count);
}
//擺放皇后,n表示擺放第n+1個皇后
public static void put(int n) {
//如果n=8,說明是第九個皇后,也就是前8個皇后已經擺好了
if(n==8) {
print();
return;
}
//否則,現在開始擺放皇后
//從每行的第一列開始放皇后,每放一個皇后就要判斷是否與已經放好的皇后衝突
for (int i = 0; i < 8; i++) {
//先把皇后放在第1列上
array[n]=i;
//如果不衝突,就可以擺放下一個皇后了,即再調用put()
if (!judge(n)) {
put(n+1);
}
//如果第i個位置不符合,那就判斷下一下個位置
//如果這一行的8個位置都不符合,那就重新擺放上一行的皇后
}
}
//判斷每次擺放的位置是否在同一列或者在同一斜線上
public static boolean judge(int n) {
//每次擺放的時候需要跟前面的n-1個皇后比較
for (int i = 0; i < n; i++) {
//如果在同一列,或者在同一斜線上,那就返回true
if(array[i]==array[n]||Math.abs(n-i)==Math.abs(array[n]-array[i])) {
return true;
}
}
return false;
}
//打印數組
public static void print() {
count++;
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]+" ");
}
System.out.println();
}
}
以上是自己對遞歸思想和8皇后問題的理解,如有錯誤之處還望指出,我會及時改正。