八皇后--N皇后问题--递归实现

八皇后问题,即在一个棋盘上,每行都可以放置一个皇后,但每个皇后都不能影响其他皇后的安全,即所有皇后的位置不能在同一直线上

解决问题方法及思想 : 递归

对每一行而言,从第一个位置进行判断,如果安全,则放置元素,如果不安全,则进行下一个位置的判断,如果本行所有位置都不安全,则返回上一行,重新寻找皇后位置,直到所有情况都寻找完毕

在使用递归之前首先要准备好两个函数实现:

1.判断此时此刻位置是否安全 (只需要判断元素上方,左上方,右上方是否安全,且只要有一个位置不安全,则结束判断!)

2.如果已经完成一个能将皇后安全放置的棋盘,则输出


完整代码:

#include <stdio.h>

#define N 8
#define boolean int
#define TRUE	1
#define FALSE	0

boolean isSafe(int (*chessboard)[N], int row, int col);
void drawChessboard(int (*chessboard)[N]);
void nQueen(int (*chessboard)[N], int row);

void nQueen(int (*chessboard)[N], int row) {
	int col;
	if(row == N) {	//如果行数到达最后一行,说明已经成功找到一个安全放置皇后的棋盘,此时输出该棋盘
		drawChessboard(chessboard);
	} else {
		for(col = 0; col < N; col++) {
			if(isSafe(chessboard, row, col)) {	//如果这个位置安全
				chessboard[row][col] = 1;	//将该位置的状态变为"有皇后"的状态,即赋值为1
				nQueen(chessboard, row + 1);	//寻找下一行皇后的位置
			}
			chessboard[row][col] = 0;   //无论本行是否安全,都应该去掉本位置的皇后,因为下一列需要放置一个皇后
		}
	}
}

void drawChessboard(int (*chessboard)[N]) {
	int i;
	int j;
	static int count = 0;	//如果不加static,则每次调用这个函数,count都会重新被赋值为0!
	printf("%d:\n", ++count);
	for(i = 0; i < N; i++) {
		for(j = 0; j < N; j++) {
			printf("%2d", chessboard[i][j]);
		}
		printf("\n");
	}
	printf("\n");
}

boolean isSafe(int (*chessboard)[N], int row, int col) {	//判断该点位置是否安全
	int i;
	int j;
	//判断元素上方是否有皇后
	for(i = row - 1, j = col; i >= 0; i--) {
		if(1 == chessboard[i][j]) {
			return FALSE;
		}
	}

	//判断元素左上方是否有皇后
	for(i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
		if(1 == chessboard[i][j]) {
			return FALSE;
		}
	}

	//判断元素右上方是否有皇后
	for(i = row - 1, j = col + 1; i >= 0 && j < N; i--, j++) {
		if(1 == chessboard[i][j]) {
			return FALSE;
		}
	}

	return TRUE;
}

int main() {
	int chessboard[N][N] = {0};		//创建一个棋盘,并将所有元素赋初值为0,如果放置皇后,则赋值为1
	nQueen(chessboard, 0);       //将棋盘地址传进,从下标为0的第一行开始进行位置判断
}

一些问题补充说明:

指针与二维数组:

int a[3][4];    a是二维数组的名字,是一个指针常量,它指向的是它所属元素的首元素,它的每一个元素是一个行数组,因此它的指针移动单位是“行”,故a+i指向的是是第i个行数组,即指向a[i]. 该过程也可以描述为: int *p;   p = a[0];

对上述a数组,行数组指针定义如下:

int(*p)[4];    表示数组*p有4个int型元素,分别为(*p)[0], (*p)[1], (*p)[2], (*p)[3], 即p指向的是有4个int型元素的一维数组,即p为行指针

此时,关于nQueen的传参问题就变得简单:

在主函数调用中 : nQueen(chessboard, 0);    chessBoard是一个二维数组名称,即一个指针常量,指向第一个行数组

而在函数实现中 : void nQueen(int (*chessBoard)[N], int row);   定义一个行指针chessBoard, 指向N个int型元素(注意形参和实参中的chessBoard是不一样的)

这样实参传的是行地址,而形参指向行元素,没有问题

猜你喜欢

转载自blog.csdn.net/szy2333/article/details/80514954