用回溯法解決八皇后問題(Java實現)

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

—-以上內容引自百度百科。

本程序的功能是打印八皇后的所有擺放方式,用回溯法解決,使用的語言是Java,主要函數在代碼中都有註釋。

主要思想是:從第0行開始擺放皇后,第0行擺放完畢後,就擺放第1行,以此類推…當第7行擺放完畢,即棋盤上已經有了8個皇后,就打印出所有皇后的路徑。接下來,就從第8個皇后開始,逐一將擺放好的皇后撤回。每撤回一個,就試探該行的其它位置(因爲我們要打印所有正確的擺法)。

程序如下:

從運行結果可以看出:八皇后共有92種擺法。

public class EightQueen{

    private static final int SIZE = 8;  //皇后的個數,此處設爲8,表示8個皇后

    private static int count = 0;  //記錄擺放的方式數

    public static void main(String[] args) {

        LinkedList<Location> list = new LinkedList<Location>();

        eightQueen(list, 0, 0);  //從棋盤的第0行第0列開始

        System.out.println("八皇后共有 " + count + "種擺放方式");

    }

    /**
     * 定義位置的數列結構,用於表示皇后的擺放位置
     */
    static class Location {
        int x ;  //對應棋盤的列
        int y ;  //對應棋盤的行

        Location(int x, int y){
            this.x = x;
            this.y = y;
        }

        @Override
        public String toString() {
            return "(" + x + ", " + y + ")";
        }
    }

    /**
     * 主要函數,用回溯法。
     */
    private static void eightQueen(LinkedList<Location> list, int x, int y) {   

        if(list.size() == SIZE){  //當list元素個數爲8時,表示8個皇后都擺放完畢,打印後即可退出函數。
            printLocation(list);  //打印皇后擺放方式
            return ;
        }

        for(int i = x ; i < SIZE ; i++){
            Location loc = new Location(i, y);
            if(isLegalLoc(list, loc)){
                list.offer(loc);  //將第y行的皇后擺放好
                eightQueen(list, 0, y+1);  //開始擺放y+1行的皇后,同樣從第0列開始擺放
                list.pollLast();  //每次擺放完一個皇后後,都要將其撤回,再試探其它的擺法。
            }                   
        }           
    }

    /**
     * 判斷位置爲loc的皇后是否合法
     */
    private static boolean isLegalLoc(LinkedList<Location> list, Location loc) {
        for(Location each : list){
            if(loc.x == each.x || loc.y == each.y)  //判斷是否在同一行或同一列
                return false;
            else if (Math.abs(loc.x - each.x) == Math.abs(loc.y - each.y))  //判斷是否在同一對角線或反對角線上
                return false;
        }
        return true;
    }

    /**
     * 打印皇后擺放方式
     * @param list
     */
    private static void printLocation(LinkedList<Location> list) {
        for(Location each : list){
            System.out.print(each.toString() + "\t");
        }
        System.out.println();
        count ++;
    }

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