题目要求:
首先国际象棋的规则:
大概意思就是:
如果一个地方有皇后,那么它的横排、纵排、左斜排和右斜排都不能放其他皇后。
运用递归回溯做(图片源自网络,侵删)
第一个皇后:
(绿的地方不能放皇后)
第二个皇后:
第三个皇后:
第四个皇后:
第五个皇后:
第六个皇后就没位置了,于是第五个皇后就不能摆放在这里,就要进行回溯
此时发现,第五个皇后摆在哪里都不能摆下八个皇后
然后就要回溯到第四个皇后:
然后放第五个皇后......
非递归回溯框架设计
首先我们可以先理解书上的八皇后代码
书(算法设计与分析第二版)P190页
首先有几点说明:
(1)(i,q(i))是皇后的位置,不用0下标,棋盘是从1~8,这时候数组就要定义成q[9];
(2)此题的要求是要找到所有的解;
(3)当第i个皇后可以放的位置都放过时,回溯到第i-1个皇后
(4)顺序是一行一行来,因为一行最多只能放一个皇后TRF
然后定义了两个函数:
dispasolution(int)就是输出八个皇后各在哪儿的函数
void dispasolution(int n) {
printf("第%d个解:",++count);
for(int i=1;i<=n;i++){
printf("(%d,%d)",i,q[i]);
}
printf("\n");
}
然后是place(int i)函数,判断当前的点是不是合法的(横竖左右斜方向有没有皇后)
这个地方很巧妙,首先这里是默认一行只有一个皇后的,所以横排不会非法
然后(q[j] == q[i])判断竖排是否非法,然后(abs(q[j]-q[i])==abs(j-i))判断左右斜排是否合法
bool place(int i) {
int j =1;
if(i==1)
return true;
while(j<i){
if((q[j] == q[i])||(abs(q[j]-q[i])==abs(j-i)))
return false;
j++;
}
return true;
}
主函数相信大家都能看得懂。
主要分析Queens()函数:
void Queens(int n){
int i=1;
q[i]=0;
while(i>=1){
q[i]++;
while(q[i]<=n&&!place(i))
q[i]++;
if(q[i]<=n){
if(i==n)
dispasolution(n);
else{
i++;
q[i]=0;
}
}
else i--;
}
}
void Queens(int n){//传入一共几个皇后
int i=1;//i表示当前行也表示第几个皇后
q[i]=0;//第i个皇后的纵坐标从0开始到n一个一个遍历,判断这个位置是否合法
上面说到:当第i个皇后可以放的位置都放过时,回溯到第i-1个皇后。while循环就是这个作用:
-
如果这个点可以,就i++,考虑下一个皇后;
-
如果这个点的所有可能都走过了,就i--,考虑上一个皇后
while(i>=1){
//这一行一个一个点开始遍历
q[i]++;
//判断这个点是否合法
while(q[i]<=n&&!place(i))
//如果不合法就继续在这一行往后遍历,找到点或者到棋盘边缘了就跳出while
q[i]++;
//判断一下上面的循环是因为到边缘跳出来的,还是找到了合法的点
//找到了合法的点
if(q[i]<=n){
//如果已经八个皇后了就打印出答案
if(i==n)
dispasolution(n);
//没到八个皇后的话就下一个皇后
else{
i++;
q[i]=0;
}
}
//这一行没有找到合法的点,返回上一个皇后
else i--;
}
运行结果:
完整代码:
#include<stdio.h>
#include<stdlib.h>
#define MAXN 9
int q[MAXN],count=0;
void dispasolution(int n) {
printf("第%d个解:",++count);
for(int i=1;i<=n;i++){
printf("(%d,%d)",i,q[i]);
}
printf("\n");
}
bool place(int i) {
int j =1;
if(i==1)
return true;
while(j<i){
if((q[j] == q[i])||(abs(q[j]-q[i])==abs(j-i)))
return false;
j++;
}
return true;
}
void Queens(int n){
int i=1;
q[i]=0;
while(i>=1){
q[i]++;
while(q[i]<=n&&!place(i))
q[i]++;
if(q[i]<=n){
if(i==n)
dispasolution(n);
else{
i++;
q[i]=0;
}
}
else i--;
}
}
int main(){
int n;
scanf("%d",&n);
Queens(n);
return 0;
}
相信理解了这个问题,上面的题目就好做了很多。
我是用的三维数组回溯做的,需要源码可以私信~