问题描述:
在8*8的国际象棋棋盘上,现要放上8个皇后,要求所有皇后都不得在同一行、一列、一斜线上,输出所有可能的放法。
方法:
逐行试探,行就不用考虑了,只需要考虑每次放置时是不是有同列、同斜线的。因为如果按照行去排,给这行放一个就可以跳到下一行了。
图:
分析:
1. 从0行开始,有8个格子,1个1个试探。(0,0)可以吗? 可以 break;
2. 到第一行:(1,0)可以吗?不可以,有重复列。 (1,1)可以吗?不可以,同斜线。 (1,2)可以吗?可以 break;
3. 到第二行:(2,0)可以吗?不可以,同列。(2,1)可以吗?不可以,同斜线。 (2,2)可以吗?不可以,同列。(2,3)可以吗?不可以,同斜线。 (2,4) 可以吗?可以 break;
4. 下一行列号都是从0开始
......
当某一行都不可以放的时候,即(j > 7)则需要回溯到上一行,给上一行的重新再挑选位置。新位置一定在之前的位置之后。
直到第7行,放置结束,输出这组解。
非递归的算法思想(输出一种结果即可):
- 行:不用管,放了就 i++ 到下一行。
- 列:有两种判断方法。
- 一:循环此列从 0 到 i-1,找这一列上有没有放过皇后。
- 二:把全部列状态存放在数组中,因为不会出现两个在一列,所以此数组只有两个状态:0 此列没有存, 1 此列存放过了
斜线:斜线分为左斜线和右斜线。左斜线如下图:
总共15条,从左到右编号0-14。与下标的关系(i+j)。0 此斜线上没有存, 1 此斜线上存放过了。
右斜线如下图:
总共15条,从右下角到左上角编号0-14。与下标的关系(7+i-j)。0 此斜线上没有存, 1 此斜线上存放过了。
Q:
栈,用于存放此次的结果,Q栈的下标代表行号,值代表此行中皇后放在 j 列。
因为如果回溯,需要用到上次的位置,属于后进先出,所以用栈。
每次准备放置一个皇后在选好的位置,就需要更新Q、col、left、right。
代码:
# include <stdio.h>
# include <stdlib.h>
// 所有都是从0开始编号
// 在c语言中,给数组赋初值时,可以只写一个,这样后面的也就系统自动赋初值为此值
int col[8] = {0,0,0,0,0,0,0,0}; //第i列有没有放皇后,0表示没放,1表示放了
int left[15] = {0}; //左斜线i上有没有皇后,0表示没放,1表示放了
int right[15] = {0}; //右斜线i上有没有放皇后,0表示没放,1表示放了
int Q[8] = {-1}; //第i行第Q【i】列上放的皇后
void Queen();
void print();
int main(void){
// 非递归遍历,此代码只显示一次的结果,要是需要所有可能结果,就需要改第一行开始放的位置
Queen(); // 调用放置皇后的函数
print(); // 调用打印函数,可打印棋盘
return 0;
}
void Queen(){
int top = -1; // 因为当回溯时,需要回到上一层的位置,并重新确定位置。Q就相当于栈,满足后进先出的特点
int i = 0; // i表示现在在判断第i行
int j = 0; // j表示现在在判断第i行的第j列
while(top != 7){// top从 -1 开始指,当指到7的时候意味着7行都已经放上了皇后,得到了一次的结果
// 试探这一行的每一列
for(;j < 8; j++){
//j为什么不能直接从0开始?因为只有到了新的一行才能从0开始,如果是回溯回来的就需要从上一次的位置向后走
if(!col[j] && !left[i+j] && !right[7+i-j]){ // 能放
// 放置皇后
Q[++top] = j;
// 修改状态
col[j] = 1;
left[i + j] = 1;
right[7+i-j] = 1;
// 走下一行
i++;
j = 0; // 新的一行j从0开始
break; // 退出for循环
}
}
// 如果是这一行都不能放,就需要回溯
if(j == 8){ // 如果不加if的话,break就会跳到这里,而不是下一层
j = Q[top--]; // 取栈顶
i--; // 退到上一层
// 上一层的改回去
col[j] = 0;
left[i + j] = 0;
right[7+i-j] = 0;
j++; // 从下一格开始走
}
}
}
// 打印函数:打印方阵
void print() {
int i,j;
printf("第1组解:\n");
for(i = 0; i < 8; i++){
for(j = 0; j < 8; j++){
if(Q[i] == j){
printf("Q ");
}else {
printf("x ");
}
}
printf("\n");
}
}
运行结果: