版权声明:转载请注明出处。 https://blog.csdn.net/baidu_38304645/article/details/83048466
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法.
输入:无
输出:8行8列的矩阵,0代表此处无皇后,1表示此处有皇后。
运行结果(由于解太多了,只放两个解吧):
算法实现:
逐行处理当前编号i的行。目标是每一行都放一个皇后。
Status Go(int a[N][N],int i){//逐行处理当前编号i的行
int j,successFlag;
for(j=0;j<N;j++){
a[i][j]=1;//尝试在第i行第j列放皇后
successFlag=Verify(a,i,j);
if(!successFlag){//不能放皇后
a[i][j]=0;
continue;
}
else if(successFlag&&i==N-1){//边界 验证合法到结束i=N-1
PrintChessBoard(a);//保存解
a[i][j]=0;
continue;
}
else if(successFlag&&i<N-1){
Go(a,i+1);//递归前进 合法从下一行开始递归
a[i][j]=0;//不管成功与否都重置
continue;
}
}
}
如何判断此处是否可以放皇后呢?判断一列中有两个皇后很简单,循环一遍统计着这一列皇后的数目就可以了。如何找到其左对角线与右对角线上的皇后呢?
我们可以通过一个规律来解决。我们可以发现,当皇后在(i,j)位置时,如果其左对角线上坐标为(x,y)就会满足表达式:
i-j = x-y
同过这个表达式可以判断一个位置是否位于皇后位置的左对角线上。同理,右对角线表达式为:
i-x = y-j;
判断是否可以放皇后 可以返回1 否则返回0
i将要行 j将要放置的列.
int Verify(int a[N][N],int i,int j){//i将要行 j1将要放置的列
//判断是否可以放皇后 可以返回1 否则返回0
int sum,x,y;
for(y=0;y<N;y++)
{//逐列检查
sum=0;
for(x=0;x<=i;x++)
sum+=a[x][y];
if(sum > 1)
return 0;
sum = 0;
for(x=0;x<i;x++)
{
if(x-y==i-j) //在其左对角线上
sum+=a[x][y];
if(i-x==y-j) //在其右对角线上
sum+=a[x][y];
}
if(sum > 0)
return 0;
}
return 1;
}
输出棋盘.
void PrintChessBoard(int a[N][N]){
//输出棋盘
num++;
int i,j;
for(i=0;i<N;i++){
for(j=0;j<N;j++){
printf("%3d",a[i][j]);
}
printf("\n");
}
printf("\n\n");
}