八皇后问题的递归与非递归算法
问题:设在初始状
态下在国际象棋棋盘上没有任何棋子(皇后)。然后顺序在第1行,第2行,…。第8行上布放棋子。在每一行中有8个可选择位置,但在任一时刻,棋盘的合法布局都必须满足3个限制条件,即任何两个棋子不得放在棋盘上的同一行、或者同一列、或者同一斜线上。
1.非递归算法:
q[n]:q[i]代表第i行的皇后在第i列
在每行插入皇后时,检查是否存在攻击。
1.检查不同列:q[i]!=q[j]
2.检查不在同一斜线上:abs(q[i]-q[j])!=abs(i-j)
abs代表正斜线反斜线都不在他们上面。
bool check(int j)//当前要插入皇后的行数
{
int i=0;
while(i<j)
{
if(q[i]==q[j]||abs(q[i]-q[j])==abs(i-j))
{
return false;
}
i++;
}
return true;
}
完整代码如下:
#include <stdio.h>
#include <stdbool.h>
#include <math.h>
#define n 8
int q[n]={-1};//第i行上的皇后在第几列
int cnt=0;
void print()
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(q[i]==j)
{
printf("1 ");//皇后放置
}
else
{
printf("0 ");//无皇后放置
}
}
printf("\n");
}
printf("\n");
}
bool check(int j)//当前要插入皇后的行数
{
int i=0;
while(i<j)
{
if(q[i]==q[j]||abs(q[i]-q[j])==abs(i-j))
{
return false;
}
i++;
}
return true;
}
void queen()
{
int i=0;
while(i>=0)//直到回溯到第一行也找不到可以放置皇后的位置,函数结束
{
q[i]++;
while(!check(i)&&q[i]<n)
{
q[i]++;//找到这一行能够放置皇后的列数
}
if(q[i]<n)
{
if(i==n-1)//最后一行也成功放置皇后,找到一个解
{
cnt++;
print();
}
else
{
i++;
}
}
else
{
q[i]=-1;//第i行到最后也没有找到合适的位置,初始化本行的列数
i--;//回到上一行,从下一列开始寻找
}
}
}
int main()
{
queen();
printf("有%d种布局",cnt);
return 0;
}
2.递归算法
col[n]:列上放的皇后
md[2n-1]:主对角线
sd[2n-1]:次对角线
q[n]:第 i行上的皇后在第几列
将上面的数组col,md,sd初始化为0,存放皇后后设置为1
当(col[j]!=1)&&(md[i+j]!=1)&&(sd[7+i-j]!=1)(i代表行,j代表列)
即代表此处可以放置皇后。
完整代码:
#include <stdio.h>
#include <stdbool.h>
#define n 8
int col[n]={0};//列上放的皇后
int md[2*n-1]={0};// 主对角线
int sd[2*n-1]={0};//次对角线
int q[n];//第 i行上的皇后在第几列
int cnt=0;
void print()
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(q[i]==j)
{
printf("1 ");//皇后放置
}
else
{
printf("0 ");//无皇后放置
}
}
printf("\n");
}
printf("\n");
cnt++;
}
void queen(int i)
{
int j;
for(j=0;j<n;j++)
{
if((col[j]!=1)&&(md[i+j]!=1)&&(sd[7+i-j]!=1))
{
q[i]=j;//放皇后
col[j]=1;
md[i+j]=1;
sd[7+i-j]=1;//标记放皇后的位置
if(i<n-1)
{
queen(i+1);
}
else
{
print();
}
col[j]=0;
md[i+j]=0;
sd[7+i-j]=0;//清除标记,开始下一组查找
}
}
}
int main()
{
queen(0);
printf("有%d种布局",cnt);
return 0;
}