分析:
对这个问题,首先我们看问题的答案,最后的结果是输出棋盘,最重要的是我们发现,最后有Queen_Max个皇后被放置好了,且每行只有一个皇后,我们很容易想到用递归解决这个问题,因为当别人帮你放好七个皇后时,你很乖就可以放好第八个,最多尝试Queen_Max次。要用递归,首先我们要想好出口,如果我们用一个数queen_number来记录已经放好的皇后的个数,不难发现,出口是当queen_number等于Queen_Max时,直接打印棋盘。要放置皇后,首先应判断,是否所选的位置能放皇后,这就要求我们写一个判断queen[x][y]是否能放皇后的函数,很容易发现这个函数中我们只要判断点(x, y)正上方,左上方,右上方三个方向是否由皇后存在,有则不能放,否则能放置。对于放置皇后的函数本人认为最难的是解决当一行都不能放置的时候,要返回上一行,而且要把上一行的皇后初始化,使要放置的位置指向原来放置皇后位置的右边,然后继续放置的问题。这一块也很难理解。
对于这一问题,因为我们使用的是递归,所以函数在调用自身时会自己保存,原来放置皇后的位置也就是下面代码的queen[x-1][i],我们要做的只是当一次调用完成时将原来放置的皇后初始化,也就是queen[x-1][i]=0,这一块我建议最好能自己调试一下,了解整个函数的过程,调试时可以把Queen_Max改成4,这样能简单一点。具体的代码如下:
#include<stdio.h>
#define Queen_Max 8
int queen_number=0; //表示已经放皇后的个数
int k=0;
int queen[Queen_Max][Queen_Max]; // 用二维数组表示棋盘
int judge_queen(int x, int y);
void place_queen(int x);
int main()
{
int i, j;
//初始化,将整个二维数组的数赋值为1
for(i=0; i<Queen_Max; i++)
for(j=0; j<Queen_Max; j++)
queen[i][j]=0;
place_queen(0);
return 0;
}
//判断queen[x][y]这个点能否方皇后,能返回1,否则返回0;
int judge_queen(int x, int y)
{
if(queen[x][y]==1) return 0;
int i, j;
//检查改点上部是不是有皇后
for(i=0; i<x; i++)
if(queen[i][y]==1) return 0;
//检查左上是否有皇后
i=x, j=y;
while(i>=0 && j>=0) {
if(queen[i--][j--]==1) return 0;
}
//检查右上是否由皇后
i=x, j=y;
while(i>=0 && j<Queen_Max) {
if(queen[i--][j++]==1) return 0;
}
return 1;
}
放置皇后,完成后并打印数组,用到了递归,x表示放置的行数
void place_queen(int x)
{
int i, j;
//出口,如果放的皇后数等于Max则打印出数组,
if(queen_number==Queen_Max) {
printf("µÚ%d×é½â\n", ++k);
for(i=0; i<Queen_Max; i++) {
for(j=0; j<Queen_Max; j++) {
printf("%2d", queen[i][j]);
}
puts(" ");
}
puts(" ");
}
//如果能queen[x][i]能放置,则将其赋值为1,用递归执行下一行,
for(i=0; i<Queen_Max; i++) {
if(judge_queen(x, i)) {
queen[x][i]=1;
queen_number++;
place_queen(++x);
queen[x-1][i]=0; //往上返回时,要恢复数组到没有执行操作之前, 一次恢复只恢复一次, 同时记录放置皇后的数减一
queen_number--;
--x;
}
}
}