回溯法求解N皇后问题

描述 :N*N的棋盘上放置N个皇后,使得任意一个皇后都不会被其它皇后吃掉(任意皇后在同行同列和对角线上不存在其它皇后)。
解法:回溯法。当前行递归去求解每一列的位置,当前行求解成功则求解下一行,失败则回溯到上一行继续求解。二维矩阵看做平面直角坐标系,使用直线方程能确定三种关系的函数式求得每个坐标的位置,遍历每个元素判断是否有解。java8实现如下:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Formatter;
import java.util.List;

public class EightQueenPuzzle {
    private int boardSize;//棋盘大小

    public int getBoardSize() {
        return boardSize;
    }

    private int[][] board;//二维素组代表棋盘
    private List matchedBoard = new ArrayList();//结果集

    public List getMatchedBoard() {
        return matchedBoard;
    }

    public EightQueenPuzzle(int boardSize) {
        this.boardSize = boardSize;
        this.board = new int[boardSize][boardSize];
    }

    private class Solution {
        private int count = 0;

        private int placeQueen(int rowIndex, int colIndex) {
            if (colIndex >= boardSize || rowIndex >= boardSize) {
                if (rowIndex < boardSize) {
                    Arrays.fill(board[rowIndex], 0);//当前行皇后重置
                }
                return boardSize;//回溯到上一行
            }
            if (!columnConflict(rowIndex, colIndex) && !slashConflict(rowIndex, colIndex)) {
                Arrays.fill(board[rowIndex], 0);//重置之前放置的皇后
                board[rowIndex][colIndex] = 1;
                if (rowIndex == boardSize - 1) {
                    count++;
                    int[][] cpy = new int[boardSize][boardSize];
                    for (int i = 0; i < boardSize; i++) {
                        cpy[i] = Arrays.copyOf(board[i], boardSize);
                    }
                    matchedBoard.add(cpy);
                    System.out.println("Placement succeed " + count + " times!");
                }
                placeQueen(rowIndex + 1, 0);
            }
            return placeQueen(rowIndex, colIndex + 1);
        }

        public void solve() {
            placeQueen(0, 0);
        }

        private boolean rowConflict(int rowIndex, int colIndex) {
            return false;
        }

        private boolean columnConflict(int rowIndex, int colIndex) {
            for (int i = 0; i < boardSize; i++) {
                if (board[i][colIndex] == 1 && i != rowIndex) return true;
            }
            return false;
        }

        //检查斜线上有无其它皇后
        private boolean slashConflict(int rowIndex, int colIndex) {
            //斜率为1的直线上检测
            int positiveD = colIndex - rowIndex;
            //斜率为-1的直线上检测
            int negativeD = colIndex + rowIndex;
            for (int i = 0; i < boardSize; i++) {
                int col = getSlashColIndex(i, positiveD, 1);
                if (col >= 0 && col < boardSize) {
                    if (board[i][col] == 1 && i != rowIndex) return true;
                }
                col = getSlashColIndex(i, negativeD, -1);
                if (col >= 0 && col < boardSize) {
                    if (board[i][col] == 1 && i != rowIndex) return true;
                }

            }
            return false;
        }

        private int getSlashColIndex(int rowX, int distance, int rate) {
            return rate * rowX + distance;
        }
    }

    public void solve() {
        for (int i = 0; i < boardSize; i++) {
            Arrays.fill(board[i], 0);
        }
        new Solution().solve();
    }

    public static void main(String[] args) {
        System.out.println("hello!!");
        EightQueenPuzzle puzzle = new EightQueenPuzzle(8);
        puzzle.solve();
        List list = puzzle.getMatchedBoard();
        System.out.println("棋盘大小为:" + puzzle.getBoardSize() + "时,N皇后问题的解有" + list.size() + "种。");
        list.forEach(puzzle::printMatrix);
    }

    public void printMatrix(int[][] matrix) {
        Formatter formatter = new Formatter(System.out);
        formatter.format("棋盘布局:%n");
        for (int i = 0; i < matrix.length; i++) {
            for (int i1 = 0; i1 < matrix[i].length; i1++) {
                formatter.format("%3d", matrix[i][i1]);
            }
            formatter.format("%n");
        }
    }
}

你可能感兴趣的:(计算机基础)