国际象棋中,若皇后出现在同一条直线或者斜线上,就会被一方吃掉,
怎样才能在一个棋盘上放下八个皇后,就是八皇后问题。
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
7 |
|
|
|
|
|
|
| Q |
6 |
|
|
|
|
| Q |
|
|
5 |
|
|
| Q |
|
|
|
|
4 |
| Q |
|
|
|
|
|
|
3 |
|
|
|
|
|
| Q |
|
2 |
|
|
|
| Q |
|
|
|
1 |
|
| Q |
|
|
|
|
|
0 | Q |
|
|
|
|
|
|
|
① Col[] :存 1 表示某列有皇后
|
|
|
|
|
|
|
|
0 1 2 3 4 5 6 7
② Left[](left = i + j): 存 1 表示某左斜线上有皇后
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
③ Right[] ( right = i - j + 7 ):存 1 表示某右斜线上有皇后
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
④ Q[] :用栈来存放每个皇后的坐标位置,回溯时栈顶指针出栈
列 | 1 | 3 | 5 | 7 | 2 | 4 | 6 | 8 |
行 0 1 2 3 4 5 6 7
寻找一个解的过程:
1.皇后栈不满时,依次在每一行的每一列找是否存在一个位置可以放下一个皇后。
2.如果可以将该位置存入皇后栈,并且更新棋盘状态(col,left,right),然后跳到下一行继续探查。
3.否则回到上一行,将皇后栈中最后存入的皇后位子出栈,将棋盘的状态回调到上一个状态,从该位置的后面继续找可以放下皇后的位置。
4.直到皇后栈存满时,找到一组解,输出棋盘状态。
代码思路:
While(皇后栈不满时){
for( 遍历所有列 ){
if(如果该位置满足条件){
更新棋盘状态;
i ++;j = 0; //跳到下一行的第一列,继续寻找合适的位置
break跳出for循环;
}
}
if(j==8){ //该行没有找到合适的位置,说明上一行的皇后位置不合适,需要改变
i--;j = Q[top--]; //回到栈顶皇后的位置;
将棋盘的状态回调到上一个状态;
j ++ 从栈顶皇后的后一个相邻位置继续寻找;
}
}
回溯都可以用递归求解
递归求所有解代码思路:
void Queen(int i){
for( int j = 0; j < 8; j++){
if((i,j)位置满足条件){
皇后放入数组;
修改棋盘状态;
if(i < 7){ //8个皇后还没找完
递归调用Queen( i+1 )函数,跳至下一行继续递归寻找;
}else{ //找完8个皇后
输出棋盘状态
}
若上一行寻找失败,或者输出完一组解后,将棋盘状态回调一次(left,right,col);
}
}
//return 若本行没有找到满足条件的位置,返回上一次递归调用点
}
递归求所有解的代码实现
#include<stdio.h>
int cnt = 0; //输出时记录状态数
int col[8] = {0}; //记录每一行中是否存有皇后
int left[15] = {0}; //记录每一左斜线中是否存有皇后
int right[15] = {0}; //记录每一右斜线中是否存有皇后
int Q[8] = {0}; //皇后栈,记录依次进栈的每个皇后的列位置
//数组在初始化时,如果初始化了第1个字符,后面的字符,系统会自动填充为0,这是一个C语言中的规定。
//统一赋值的方法: memset(arrName, 'M', sizeof(arrName));
//输出
void Print(int Q[]){
printf("\n第%d种棋盘状态:\n\n",++cnt);
printf("*****************\n");
for(int i = 7; i > -1; i--){
printf("|");
for(int j = 0; j < 8; j++){
if(j == Q[i])
printf("Q|");
else
printf("X|");
}
printf("\n");
}
printf("*****************\n");
}
void Queen(int i){
for(int j = 0; j < 8; j++){ //在某行中找可以放下皇后的位置
if((!col[j]) && (!left[i+j]) && (!right[i-j+7])){ //如果第i行第j列满足放下皇后的条件
//更新棋盘状态
col[j] = 1;
left[i+j] = 1;
right[i-j+7] = 1;
Q[i] = j; //把皇后放下
if(i < 7){ //如果8个皇后还没找完则
Queen(i+1); //递归,跳至下一行继续递归寻找
}
else{ //找完8个皇后即求得一组解,将其输出
Print(Q);
}
//若上一行寻找失败,或者输出完一组解后,将棋盘状态回调一次
col[j] = 0;
left[i+j] = 0;
right[i-j+7] = 0;
}
}
//return 本行没有找到满足条件的位置,返回上一次递归调用点
}
int main(void){
printf("递归求解八皇后问题\n");
Queen(0);
printf("\n以上是求得所有解\n");
}