C语言 N皇后问题
介绍:什么是N皇后问题
- 国际象棋中,皇后是一个很强力的单位,可以朝着以皇后棋子本身位置为中心,横向和纵向以及 斜率为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 <bits/stdc++.h>//偷懒用了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<<cnt;
return 0;
}
以上!
希望能给你一点帮助。
感谢