天天看點

八皇後問題(回溯算法)

八皇後問題(回溯算法)

問題描述

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

思路分析

  1. 第一個皇後先放第一行第一列
  2. 第二個皇後放在第二行第一列、然後判斷是否OK,如果不OK,繼續放在第二列、第三列、依次把所有列都放完,找到一個合适
  3. 繼續第三個皇後,還是第一列、第二列…….直到第8個皇後也能放在一個不沖突的位置,算是找到了一個正确解
  4. 當得到一個正确解時,在棧回退到上一個棧時,就會開始回溯,即将第一個皇後,放到第一列的所有正确解,全部得到.
  5. 然後回頭繼續第一個皇後放第二列,後面繼續循環執行1,,2,3的步驟

說明: 理論上應該建立一個二維數組來表示棋盤,但是實際上可以通過算法,用一個一維數組即可解決問題。arr[8]={0,4,7,5,2,6,1,3}//對應arr下标 表示第幾行,即第幾個皇後,arr[i]=val,val表示第i+1個皇後,放在第i+1行的第val+1列。

八皇後問題(回溯算法)

代碼實作

package com.recursion;

public class Queue8 {

	// 定義一個max表示共有多少個皇後
	int max = 8;
	// 定義一個array,儲存皇後放置位置的結果,比如arr= {0,4,7,5,2,6,1,3}
	int[] array = new int[max];
	static int count = 0;
	static int judgeCount = 0;

	public static void main(String[] args) {
		// 測試八皇後
		Queue8 queue8 = new Queue8();
		queue8.check(0);
		System.out.println("一共有" + count + "解法");
		System.out.println("一共判斷沖突" + judgeCount + "次");
	}

	// 方法:放置第n個皇後
	// 特别注意:check是每一次遞歸時,進入到check中都有for (int i = 0; i < max; i++),是以産生回溯
	private void check(int n) {
		if (n == max) {// n=8,八個皇後就已經放好了
			print();
			return;
		}
		// 依次放入皇後,并判斷是否沖突
		for (int i = 0; i < max; i++) {
			// 先把目前皇後你,放到該行的第一列
			array[n] = i;
			// 判斷當放置第n個皇後到i列時,是否沖突
			if (judge(n)) {// 不沖突
				// 接着放n+1個皇後,即開始遞歸
				check(n + 1);
			}
			// 如果沖突,就繼續執行array[n]=i;即将第n個皇後,放置在本行的後移的一個位置
		}
	}

	// 檢視當我們放置第n個皇後,就去檢測該皇後是否和前面已經擺放的皇後沖突
	/**
	 * @param n 表示第n個皇後
	 * @return
	 */
	private boolean judge(int n) {
		judgeCount++;
		for (int i = 0; i < n; i++) {
			// 說明:
			// 1.array[i] == array[n] 判斷是否在同一列
			// 2.Math.abs(n - i) == Math.abs(array[n] - array[i]) 判斷是否在同一斜線
			// 3.判斷是否在通一行,沒有必要,n每次都在遞增。
			if (array[i] == array[n] || Math.abs(n - i) == Math.abs(array[n] - array[i])) {
				return false;
			}
		}
		return true;
	}

	// 先寫一個方法可以将皇後擺放的位置輸出
	private void print() {
		count++;
		for (int i = 0; i < array.length; i++) {
			System.out.print(array[i] + " ");
		}
		System.out.println();
	}
}
           

繼續閱讀