描述 :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<int[][]> matchedBoard = new ArrayList();//结果集
public List<int[][]> 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<int[][]> 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");
}
}
}