Go、java實現八皇后問題

題目描述

八皇后問題,一個古老而著名的問題,是回溯算法的典型案例。該問題由國際西洋棋棋手馬克斯·貝瑟爾於 1848 年提出:在 8×8 格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法。高斯認爲有 76 種方案。1854 年在柏林的象棋雜誌上不同的作者發表了 40 種不同的解,後來有人用圖論的方法解出 92 種結果。計算機發明後,有多種計算機語言可以編程解決此問題。

思路

1. 確定數據結構

  1. 初看題意,8*8的棋盤,果斷用二維數組!定義落子的地方將二維數組的座標改變即可。
  2. 使用二維數組固然是沒有任何問題,但是卻可以進行簡化。因爲沒兩個皇后不能再同一行或者同一列,那麼,我們以一維數組的下標來記錄行數,以一位數組的下標所在的值記錄該行皇后所在列數,那麼 index - value 就可以表現出皇后的座標
  3. 綜上所述,我們使用一維數組來記錄皇后位置,以index記錄第幾個皇后,在第幾行(默認第幾個皇后就在第幾行),該下標所在的值記錄皇后所在的列數,以index - value記錄皇后的座標

2. 具體實現思路

  1. 首先,我們定義一個可以將一維數組打印出來的方法:
    print(數組)
  2. 其次,我們來判斷當前第n個皇后與從第0個皇后開始之間的所有皇后是否處於同一行、同一列、同一斜線。
    2.1 同一行不需要判斷,因爲默認一個皇后一行,不可能同行
    2.2 判斷是否爲同一個斜線 因爲棋盤是正方形棋盤,那麼當兩個皇后的橫座標與縱座標相減相等時,其與他們的相交點會組成一個等腰直角三角形,此時,他們處於同一斜線上:如下圖

在這裏插入圖片描述

  1. 之後就是將皇后棋落子,從0開始循環到8,給第n個皇后分別賦值爲i(i爲當前循環到第幾個),之後進行判斷,是否能落子,如果能落子,那麼將n+1,繼續落子,即遞歸調用。
  2. 回溯 當第n個子不滿足時,該方法結束,返回調用它的方法,這時,調用它的方法會進入其方法體內的for循環,將此皇后換一個位置落,若再不行,則又會回溯。

代碼

java版本

public class Queen8 {
    private static int[] array = new int[8];
    private static int count = 0;
    public static void main(String[] args) {
        Queen8 queen8 = new Queen8();
        queen8.put(0);
        System.out.println(count);
    }

    private void put(int n){
        if (n == 8){
            print();
            count++;
            return;
        }
        for (int i = 0; i < 8; i++){
            array[n] = i;
            if (check(n)){
                put(n + 1);
            }
        }
    }

    /**
     * 校驗是否能落子
     * @param n 第n+1個皇后
     * @return 返回true 能落子 false 不能落子
     */
    private boolean check(int n){
        for (int i = 0; i < n; i++){
            if (array[i] == array[n] || Math.abs(array[i] - array[n]) == Math.abs(i - n)){
                return false;
            }
        }
        return true;
    }

    /**
     * 打印數組
     */
    private void print(){
        for (int i = 0; i < array.length; i++){
            System.out.print(array[i]+"\t");
        }
        System.out.println();
    }

    
}

Go版本

package main

import (
	"fmt"
)
//八皇后問題


//記錄打印總次數
var count int = 0
//使用一維數組表示棋盤 第i個元素表示第i個皇后,第i行,值表示該皇后在第幾列
var data []int = make([]int, 8)
func main(){

	


	put(0)
	fmt.Println(count)
}
//思路: 首先,需要有一個放置皇后的方法
func put(n int){
	//當放置的n爲8時,即爲第9個皇后  因爲數組從0開始
	if (n == 8){
		fmt.Println(data)
		count++
		return
	}
	//如果不是第9個皇后,那麼就遍歷來放置第1到8個皇后
	for i := 0; i < 8; i ++{
		//先把當前的子n 放在i這個位置上
		data[n] = i
		//判斷該點是否可以進行落子
		if (check(n)){
			put(n + 1)
		}
	}
}

//檢查皇后是否在同一列或者在同一斜線
func check(n int) bool{
	for i := 0; i < n; i++{
		//第一個 data[i] == data[n]  我們此處用下標代表第幾行  用數值代表第幾列  那麼當第i行的皇后與第n行的皇后在同一列
		//就不符合題意了
		//第二個  abs(data[n] - data[i]) == abs(i - n)   n 和 i代表皇后的橫座標  data[n] data[i]代表皇后的縱座標  那麼兩個皇后橫座標相減  縱座標相減相同時
		//其兩個皇后構成了一個與棋盤45°的夾角,棋盤是正方形,所以 此時兩個皇后處在同一斜線上
		if (data[i] == data[n] || abs(data[n] - data[i]) == abs(i - n)){
			return false
		}
	}
	return true
}


//goLang沒有整數的取絕對值方法  自己寫一個
func abs(n int) int{
	if (n < 0){
		return -n
	}
	return n
}

天行健,君子以自強不息,地勢坤,君子以厚德載物。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章