问题描述:
在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]