1. 程式人生 > >使用回溯法解決八皇后問題(同樣適用於N皇后)。

使用回溯法解決八皇后問題(同樣適用於N皇后)。

在學習資料結構的時候,看到了一道八皇后的問題。寫完後,再去網上檢視發現原來這個問題有這麼多的優化解法,相比之下相形見絀。但我還是記錄下來,有興趣的小夥伴可以看看。
先大致說下我的思路
建立一個初始化值為0的8x8的陣列,0代表無皇后且不在其他皇后的攻擊範圍,-1代表皇后的位置,>0的整數代表格子在皇后的攻擊範圍。例如某個格子的數字為3說明該格子在3個皇后的攻擊範圍。
當遍歷到二維陣列的某個位置值為0,說明該位置安全,即可放置皇后,把皇后的位置設定為-1,並把該位置的豎,橫,斜方向的格子全都+1,然後就直接跳到下一行繼續查詢合適的位置放置下一個皇后。假如該行查詢完後並沒有合適的位置,這時候就會回溯上一行,先把上一行當前皇后位置設定為0,並把該位置的豎,橫,斜方向的格子全都-1,繼續往右邊格子遍歷…….以此類推。
下面是程式碼,最後求出8皇后一共有92種可能(沒排除對稱)
同樣適用於求N皇后。

import java.util.ArrayList;
import java.util.List;

/**
 * 八皇后問題(N皇后問題)
 */
public class EightQueens {

    private static List<int[][]> list = new ArrayList<int[][]>();

    private static int[][] checkerboard;

    /** N代表皇后個數 */
    private static int N;

    public void judge(int i, int
j) { if(checkerboard[i][j] != 0) { checkerboard[i][j]++; } else { checkerboard[i][j] = 1; } } /** * 把原來該格子所在的皇后標識和攻擊範圍去除。 */ public void toBack(int i, int m) { for(int j = 0; j < N; j++) { checkerboard[m][j]--; checkerboard[j][i]--; } for
(int x = i, y = m; x >=0 && y < N; x--, y++) { checkerboard[y][x]--; } for(int x = i, y = m; x < N && y < N; x++, y++) { checkerboard[y][x]--; } for(int x = i, y = m; x < N && y >= 0; x++, y--) { checkerboard[y][x]--; } for(int x = i, y = m; x >= 0 && y >= 0; x--, y--) { checkerboard[y][x]--; } checkerboard[m][i] = 0; } public boolean search(int m) { for(int i = 0; i < N; i++) { if(checkerboard[m][i] == 0) { //在二位陣列中把攻擊範圍和皇后位置加上標識 for(int j = 0; j < N; j++) { judge(m, j); judge(j, i); } for(int x = i, y = m; x >=0 && y < N; x--, y++) { judge(y, x); } for(int x = i, y = m; x < N && y < N; x++, y++) { judge(y, x); } for(int x = i, y = m; x < N && y >= 0; x++, y--) { judge(y, x); } for(int x = i, y = m; x >= 0 && y >= 0; x--, y--) { judge(y, x); } checkerboard[m][i] = -1; //當m>=N說明一種情況完成,繼續判斷下一種情況 if(++m >= N) { //輸出該可能的皇后位置排列 /* System.out.println("num: " + list.size() + "--------------------------"); for(int x = 0; x < N; x++) { for(int y = 0; y < N; y++) { if(checkerboard[x][y] < 0) { System.out.print("1 "); } else { System.out.print("0 "); } } System.out.println(); } */ list.add(checkerboard); //把當前位置的皇后標識和攻擊範圍去除 toBack(i, --m); //繼續下一格 continue; } //遞迴往下層走 if(!search(m)) { //回溯 toBack(i, --m); } else { return true; } } } return false; } public static void main(String[] args) { EightQueens eightQueens = new EightQueens(); for(int i = 1; i <= 14; i++) { N = i; checkerboard = new int[i][i]; eightQueens.search(0); System.out.println(i + "皇后一共有" + list.size() + "種可能"); list.clear(); } } }

輸出結果

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種可能