巧解八皇后问题

 问题描述:

    在8*8的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一个斜线上,文有多少中解法?

 

问题分析:

  • 如果用暴力求解发,则时间复杂度为:8*8的棋盘,一共有64个位置,有8为皇后,所以本质是将8位皇后放在64个位置上,即从64个位置中选择8个位置。所以总的搜索空间为:C864。
  • 但是这个问题有很多限制条件,我们将这些限制条件加上之后,就可以大大的降低解空间:
    • 同一行中不能放两个皇后,即每行只能放一个皇后。因此我们可以将8*8的矩阵缩减成一个8维的数组,表示一行只能放置一个皇后,其中数组的值表示:a[i] = j表示第i行在第j列上放置一个皇后;
    • 然后我们需要用3个额外的辅助数组来保存列的放置情况,主对角线的放置情况,次对角线的放置情况:
      • 一共8列,因此用一个8维的boolean型数组记录当前列是否有皇后已经放置;
      • 对角线的问题略有复杂,但是仍然可以分析得出横纵坐标之间的关系:假设在我们放置皇后的数组中,a[3] = 2, 也就是说明:
        • 对于主对角线来说:所有a[1][0], a[2][1], a[4][3], a[5][4], a[6][5], a[7][6]不能再放置皇后,可以发现他们横纵坐标的关系为:x-y=1始终成立,因此我们得出如果a[i] = j, 则所有i-j的位置都不能再放置皇后,而对于8*8的棋盘来说,-7<=x-y<=7, 即-(N-1)<=x-y<=N-1, 即 0<=x-y+N-1 <=2N-2,所以申请一个长度为2N-1的数组来记录主对角线的摆放情况;
        • 对于次对角线来说:所有a[0][5], a[1][4], a[2][3], a[4][1], a[5][0]都不能再放置皇后,可以发现他们横纵坐标的关系为:x+y=5始终成立,因此我们得出如果a[i] = j,则所有i+j的位置都不能再放置皇后,而对于8*8的棋盘来说,0<=x+y<=2N-2,所以申请一个长度为2N-1的数组来记录次对角线的摆放情况。
      • 用深度优先搜索的思路,每次走到一条思路或者终点,需要回溯。所以代码为:递归+回溯。

 

          

package com.eight;

import java.util.ArrayList;
import java.util.Arrays;

class EightQueen {
    private int N; //The number of queens.
    private boolean[] column;
    private boolean[] maind;
    private boolean[] secondaryd;
    private ArrayList<int[]> result = new ArrayList<int[]>();
    
    
    
    /**
     * Initial the column, main diagonal, secondary diagonal to false,
     * which means there is no queen everywhere.
     * @param N
     */
    public void initQ(int N) {
        this.N = N;
        column = new boolean[N];
        maind = new boolean[2 * N - 1];
        secondaryd = new boolean[2 * N - 1];
        int i = 0;
        for(i=0; i<column.length; i++)
            column[i] = false;
        for(i=0; i<maind.length; i++)
            maind[i] = false;
        for(i=0; i<secondaryd.length; i++)
            secondaryd[i] = false;
    }
    
    /**
     * the main function of lay queens.
     */
    public void queens() {
        int[] path = new int[N];
        calcQueen(path, 0);
    }

    private void calcQueen(int[] path, int row) {
        // TODO Auto-generated method stub
        if(row == N) {
            result.add(path);
            System.out.println(Arrays.toString(path));
            return;
        }
        for(int col=0; col<N; col++) {
            if(canLay(row, col)) {
                path[row] = col;
                column[col] = true;
                maind[row-col+N-1] = true;
                secondaryd[row+col] = true;
                calcQueen(path, row+1);
                
                //BackTracking, important!!
                column[col] = false;
                maind[row-col+N-1] = false;
                secondaryd[row+col] = false;
            }
        }
    }

    /**
     * Judge if the position can lay a queen.
     * @param row
     * @param col
     * @return
     */
    private boolean canLay(int row, int col) {
        // TODO Auto-generated method stub
        return (!column[col] && !secondaryd[row+col] && !maind[row-col+N-1]);
    }
    
    
    public ArrayList<int[]> getResult() {
        return result;
    }
}



public class Queens {

    public static void main(String[] args) {
        EightQueen q = new EightQueen();
        q.initQ(8); // It is a eight queens problem.
        q.queens();
        
    }

}
//Some output instances:
[0, 4, 7, 5, 2, 6, 1, 3]
[0, 5, 7, 2, 6, 3, 1, 4]
[0, 6, 3, 5, 7, 1, 4, 2]
[0, 6, 4, 7, 1, 3, 5, 2]
[1, 3, 5, 7, 2, 0, 6, 4]
[1, 4, 6, 0, 2, 7, 5, 3]
[1, 4, 6, 3, 0, 7, 5, 2]
[1, 5, 0, 6, 3, 7, 2, 4]
[1, 5, 7, 2, 0, 3, 6, 4]
[1, 6, 2, 5, 7, 4, 0, 3]
[1, 6, 4, 7, 0, 3, 5, 2]
[1, 7, 5, 0, 2, 4, 6, 3]
[2, 0, 6, 4, 7, 1, 3, 5]

 

posted @ 2016-05-10 15:57  江湖小妞  阅读(605)  评论(0编辑  收藏  举报