- 国际象棋中,皇后是一个很强力的单位,可以朝着以皇后棋子本身位置为中心,横向和纵向以及 斜率为1和-1的方向上移动,N 皇后问题是指在 n * n 的棋盘上要摆 n 个皇后,并且使得任何两个 皇后不同行,不同列也不在同一条斜线上。
这个问题我用的是回溯的方法:
以4x4的棋盘为例:
我们先在第一行取第一列的位置,此位置没有与其他皇后行走范围冲突,因此可以放
| 1 | 2 | 3 | 4 | |
|---|---|---|---|---|
| 1 | Q | q | q | q |
| 2 | q | q | ||
| 3 | q | q | ||
| 4 | q | q |
第二行同样从第一列开始取,当取到第一列,冲突,第二列,冲突,第三列不冲突,放置第二枚皇后
| 1 | 2 | 3 | 4 | |
|---|---|---|---|---|
| 1 | Q | q | q | q |
| 2 | q | q | Q | q |
| 3 | q | q | q | q |
| 4 | q | q | q |
第三行重复第二行的操作,但是发现任何列都会冲突,因此不能放,我们回到第二行,将皇后向下一列放置
再来到第三行此时第二列没有冲突,则可以放
| 1 | 2 | 3 | 4 | |
|---|---|---|---|---|
| 1 | Q | q | q | q |
| 2 | q | q | q | Q |
| 3 | q | Q | q | q |
| 4 | q | q | q | q |
我们发现第四行又没有可选择的了。第一次重试失败,回溯上一级,无可用列,再回溯上一级,无可用列,最后返回第一行。
第二次重试
我们重新回到第一步,这说明我们之前第一行选择第一列是无解的,所以我们第一行不应该选择第一列,我们再来选择第二列来试试,以此类推
| 1 | 2 | 3 | 4 | |
|---|---|---|---|---|
| 1 | q | Q | q | q |
| 2 | q | q | ||
| 3 | q | q | ||
| 4 | q |
代码实现如
#include//偷懒用了C++的万能头,其实和C没区别,.C文件编译不通过就换C的头 using namespace std; bool attack(int *chess, int col, int row) { for(int i = 0; i < row; ++i){ if(chess[i] == col){//纵向冲突 return true; } if(col - chess[i] == row - i || chess[i] - col == row - i){ //斜线冲突 return true; } } return false; } int nqueen() { int queens = 0; cin>>queens; int col = 0, cnt = 0, row = 0; int chess[9] = {-1}; //题目要求是最多9个皇后,而且网站的编译器不允许数组长度为变量。 while(!(col == queens && row == 0)){ if(!attack(chess,col,row)){//判断无冲突 chess[row++] = col; if(row == queens){//已将所有皇后防止完成 ++cnt; col = chess[--row];//回溯上一行寻找新解 ++col; while(col == queens){//上一行已经是最后一个的情况则再向上回溯 if(queens == 1){ col = queens; row = 0; break; } chess[row--] = -1; col = chess[row]; col++; } } else{ col = 0; } } else{ ++col;//有冲突则下一列 while(col == queens && row != 0){//全列都有冲突则回溯 chess[row--] = -1; col = chess[row]; col++; } } } return cnt; } int main() { int cnt = 0; cnt = nqueen(); cout< 以上! 希望能给你一点帮助。
感谢



