【C语言>数据结构与算法的应用3】八皇后问题---递归实现(C语言)

什么是八皇后问题?

8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上(在国际象棋中,皇后可以可横直斜走,且格数不限,吃子与走法相同),问有多少种摆法?

该怎么解决八皇后问题?

我们要解决这个问题,首先要先想到棋盘要怎么表示,因为我们要棋盘上摆放皇后,看有几种摆法?
这里我们用二维数组来表示棋盘,只要申请一个8*8大小的数组,就可以表示棋盘了。

#define width 8
boolean ChessBoard[width][width]; //width = 8

这里的boolean是类型定义(其实就是unsigned char ChessBoard[8][8]),而这个类型定义是在mec.h中:

#ifndef _MEC_H_
#define _MEC_H_

typedef unsigned char boolean; //类型定义
#define		TRUE		1
#define		FALSE		0

#define		NOT_FOUND	-1

#define SETB(value, index)	(value |= 1 << ((index) ^ 7))
#define CLRB(value, index)	(value &= ~(1 << ((index) ^ 7)))
#define GETB(value, index)	(((value) & (1 << ((index) ^ 7))) != 0)

int skipBlank(const char *str);
boolean isRealStart(int ch);

#endif

棋盘表示结束了,我们如何表示皇后呢?
很简单,我们在二维数组中用 “1” 表示皇后,用 “0” 表示没有皇后。
刚开始时,棋盘中没有皇后,全都是“ 0 ”:

boolean ChessBoard[width][width] = {0}; //width = 8 

棋盘和皇后的表示解决后,下面就是该如何判断皇后放在安全的位置,让任意两个皇后都不能处于同一行、同一列或同一斜线上。我们上面已经用“ 1 ”表示有皇后了,所以这里我们只需要判断我们即将放皇后的位置的左上方、上方、右上方有没有皇后。若有,则此位置不能放皇后;若无,则此位置可以放皇后。
代码如下:

boolean isSafe(boolean (*ChessBoard)[width], int row, int col)
{
	int i;
	int j;
	
	for (i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--)//判断左上方
	{
		if (ChessBoard[i][j] == 1)
		{
			return FALSE;
		}
	}
	for (i = row - 1, j = col; i >= 0; i--) //判断上方
	{
		if (ChessBoard[i][j] == 1)
		{
			return FALSE;
		}
	}
	for (i = row - 1, j = col + 1; i >= 0 && j < width; i--,  j++)//判断右上方
	{
		if (ChessBoard[i][j] == 1)
		{
			return FALSE;
		}
	}
	return TRUE;
}

在完成这个判断后,下面就要使用递归来完成对皇后的摆放。

void chess(boolean(*ChessBoard)[width], int row)
{
	int col;

	if (row >= width) //当row = 8时,八皇后已经摆放成功了。这就是一种解法。
	{
		showChess(ChessBoard);//我们把它输出。
		return;
	}
	for (col = 0; col < width; col++) //从一行一列到一行八列判断是否安全。
	{
		if (isSafe(ChessBoard, row, col)) //如果安全,这个位置赋值1,表示已经放皇后了
		{
			ChessBoard[row][col] = TRUE;
			chess(ChessBoard, row + 1); //开始递归,第一次递归时,(row + 1) = 2,所以在递归函数中,row = 2, 然后从二行一列到二行八列判断是否安全.....
			ChessBoard[row][col] = FALSE; //当调用的递归函数结束后,都要返回这里把这个位置赋值为零。因为这个递归调用如果结束了,证明有两种可能:
			//1、八皇后已经摆放成功,这需要尝试下一种解法,这个位置需要赋值为零。
			//2、八皇后摆放不成功(即在某一行,任何一个位置通过isSafe()判断都不安全),这需要尝试下一种摆放方法,这个位置需要赋值为零。
		}
	}
}

如果上述代码和注释看的不太明白的话,建议在纸上把棋盘画出来,按照代码递归的进行一遍。

完整代码

#include<stdio.h>
#include "mec.h" //这里的mec.h的代码在上面,需要创建一个 .h 的头文件,才可以编译。

#define   width     8

boolean isSafe(boolean(*ChessBoard)[width], int row, int col);
void showChess(boolean(*ChessBoard)[width]);
void chess(boolean(*ChessBoard)[width], int row);

void chess(boolean(*ChessBoard)[width], int row)
{
	int col;

	if (row >= width)
	{
		showChess(ChessBoard);
		return;
	}
	for (col = 0; col < width; col++)
	{
		if (isSafe(ChessBoard, row, col))
		{
			ChessBoard[row][col] = TRUE;
			chess(ChessBoard, row + 1);
			ChessBoard[row][col] = FALSE;
		}
	}
}

void showChess(boolean(*ChessBoard)[width])
{
	int i;
	int j;
	 static int count = 0;

	printf("第%d个解 :\n", ++count);
	for (i = 0; i < width; i++)
	{
		for (j = 0; j < width; j++)
		{
			printf("%5d ", ChessBoard[i][j]);
		}
		printf("\n");
	}
}

boolean isSafe(boolean (*ChessBoard)[width], int row, int col)
{
	int i;
	int j;
	
	for (i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) //判断左上方
	{
		if (ChessBoard[i][j] == 1)
		{
			return FALSE;
		}
	}
	for (i = row - 1, j = col; i >= 0; i--) //判断上方
	{
		if (ChessBoard[i][j] == 1)
		{
			return FALSE;
		}
	}
	for (i = row - 1, j = col + 1; i >= 0 && j < width; i--,  j++) 判断右上方
	{
		if (ChessBoard[i][j] == 1)
		{
			return FALSE;
		}
	}
	return TRUE;
}

int main()
{
	boolean ChessBoard[width][width] = {0};
	
	chess(ChessBoard, 0);

	return 0;
}

最后,感谢~铁血教主 !

有问题可以评论留言~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值