0
点赞
收藏
分享

微信扫一扫

也来说一下八皇后问题

 

(见上面给出的链接),里面讲到了回溯算法八皇后问题。仔细阅读全文之后,发现作者所写与实际开发工作还是有一定的差别,因此特发此文,表达一下个人的看法,请各位批评指正。

       什么是回溯算法?举个例子来说,当你走到一个有很多岔路的路口,不知道哪条路是通的,于是,你随便选择了一条,当走到路的尽头发现无路可走时,便回过头来选择另外的一条路走,直到走通某条路为止。有关回溯和八皇后问题的详细描述,请见原文。

       在回溯算法中,利用了递归的思想。但是,在实际的软件开发项目中,我们要慎用递归来编写代码,原因是:

       第一,我们日常写代码编函数有时并不确定是谁什么时候来调用,所以递归一般不用。教科书上的东西教的是方法和理论,用来做单项训练是很有必要的,但是实际工作中考虑的因素就多得多,可用性、可测试性、可移植性、高性能、规范性等等都很重要。因为产品研发总是算成本的,但是如果有短板迟早会付出代价的。

       第二,如果递归的次数过多,会造成程序栈的耗尽。同时,要限制递归使用的范围,防止出现异常。实际上所有递归都可以用非递归方式实现,并且一般非递归的效率更高。

       好了,别的不说了。本人对原文中的代码进行了一定的改进,最终代码如下所示:

/**********************************************************************
*版权所有 (C)2014, Zhou Zhaoxiong。
*
*文件名称: Eight.c
*文件标识:无
*内容摘要:用于实现八皇后问题
*其它说明:无
*当前版本: V1.0
*作 者: Zhou Zhaoxiong
*完成日期: 20140418
*
*修改记录1://修改历史记录,包括修改日期、版本号、修改人及修改内容
*修改日期:
*版本号:
*修改人:
*修改内容:
*
**********************************************************************/

#include <stdio.h>

typedef unsigned char UINT8;
typedef unsigned int UINT32;
typedef signed int INT32;
typedef void VOID;
typedef UINT8 BOOL;

#define QueenNum 8 //八皇后

#define TRUE (BOOL)1
#define FALSE (BOOL)0

UINT8 g_szBoard[QueenNum+2][QueenNum+2] = {0};
UINT32 g_ConditionCount = 0; //记录八皇后的情况个数

typedef struct _tag_pos //定义一个数据结构来充当方向
{
UINT32 iHorizontal;
UINT32 iVertical;
}TPos;

//检测三个方向:左上,右上,正上(横排是不检测的,因为一排只放一个)
TPos tPos[3] = {{-1,-1}, {-1,1}, {-1,0}};

//函数声明
VOID InitBoard();
VOID DisplayBoard(UINT32 iHorizontal, UINT32 iVertical);
BOOL CheckBoard(UINT32 iHorizontal, UINT32 iVertical);
VOID FindBoard(UINT32 iLine, UINT32 iHorizontal, UINT32 iVertical);
INT32 main();


/**********************************************************************
*功能描述:初始化棋盘
*输入参数: 无
*输出参数:无
*返回值:无
*其它说明:无
*修改日期 版本号 修改人 修改内容
* ------------------------------------------------------------------------------------------------------
* 20140418 V1.0 zzx 创建
***********************************************************************/
VOID InitBoard()
{
UINT32 iHorizontal = 0;
UINT32 iVertical = 0;

for (iHorizontal = 0; iHorizontal < QueenNum + 2; iHorizontal ++)
{
g_szBoard[0][iHorizontal] = '#';
g_szBoard[QueenNum+1][iHorizontal] = '#';
g_szBoard[iHorizontal][0] = '#';
g_szBoard[iHorizontal][QueenNum+1] = '#';
}

for (iHorizontal = 1; iHorizontal <= QueenNum; iHorizontal ++)
{
for (iVertical = 1; iVertical <= QueenNum; iVertical ++)
{
g_szBoard[iHorizontal][iVertical] = ' ';
}
}
}


/**********************************************************************
*功能描述:打印棋盘内容
*输入参数: iHorizontal-水平位置
iVertical-垂直位置
*输出参数:无
*返回值:无
*其它说明:无
*修改日期 版本号 修改人 修改内容
* ------------------------------------------------------------------------------------------------------
* 20140418 V1.0 zzx 创建
***********************************************************************/
VOID DisplayBoard(UINT32 iHorizontal, UINT32 iVertical)
{
UINT32 iLoopOuter = 0;
UINT32 iLoopInner = 0;

if (g_szBoard[iHorizontal][iVertical] == '*')
{
for (iLoopOuter = 0; iLoopOuter < QueenNum + 2; iLoopOuter ++)
{
for (iLoopInner = 0; iLoopInner < QueenNum + 2; iLoopInner ++)
{
printf("%c ", g_szBoard[iLoopOuter][iLoopInner]);
}

printf("\n");
}
}
}


/**********************************************************************
*功能描述:检查是否可以放皇后
*输入参数: iHorizontal-水平位置
iVertical-垂直位置
*输出参数:无
*返回值: TRUE-可以放置皇后 FALSE-不能放置皇后
*其它说明:无
*修改日期 版本号 修改人 修改内容
* ------------------------------------------------------------------------------------------------------
* 20140418 V1.0 zzx 创建
***********************************************************************/
BOOL CheckBoard(UINT32 iHorizontal, UINT32 iVertical)
{
UINT32 iPos = 0; //表示方向
BOOL bRetFlag = TRUE;

for (iPos = 0; iPos < 3; iPos ++) //检测三个方向
{
UINT32 iHorizontalNew = iHorizontal;
UINT32 iVerticalNew = iVertical;

while (bRetFlag && (g_szBoard[iHorizontalNew][iVerticalNew] != '#')) //判断有没有到达棋盘边界
{
iHorizontalNew = iHorizontalNew + tPos[iPos].iHorizontal;
iVerticalNew = iVerticalNew + tPos[iPos].iVertical;

bRetFlag = bRetFlag && (g_szBoard[iHorizontalNew][iVerticalNew] != '*'); //判断这个方向有没有放过皇后
}
}

return bRetFlag; //可以放皇后返回TRUE,不可返回FALSE
}


/**********************************************************************
*功能描述:查找皇后的放置位置并放置皇后
*输入参数: iLine-行位置
iHorizontal-水平位置
iVertical-垂直位置
*输出参数:无
*返回值:无
*其它说明:无
*修改日期 版本号 修改人 修改内容
* ------------------------------------------------------------------------------------------------------
* 20140418 V1.0 zzx 创建
***********************************************************************/
VOID FindBoard(UINT32 iLine, UINT32 iHorizontal, UINT32 iVertical)
{
UINT32 iRow = 0;

if (iLine > QueenNum) //判断是否已经超过了第八行
{
if (g_szBoard[iHorizontal][iVertical] == '*') //当该位置处有皇后时,才打印棋盘
{
g_ConditionCount ++; //计算八皇后情况的个数

DisplayBoard(iHorizontal, iVertical);
}
}
else
{
for (iRow = 1; iRow <= QueenNum; iRow ++) //判断一行是否有匹配的位置
{
if (CheckBoard(iLine, iRow))
{
g_szBoard[iLine][iRow] = '*'; //放置皇后
FindBoard(iLine+1, iHorizontal, iVertical);
g_szBoard[iLine][iRow] = ' '; //清除放错的皇后
}
}
}
}


/**********************************************************************
*功能描述:主函数
*输入参数:
*输出参数:无
*返回值: 0-执行完毕
*其它说明:无
*修改日期 版本号 修改人 修改内容
* ------------------------------------------------------------------------------------------------------
* 20140418 V1.0 zzx 创建
***********************************************************************/
INT32 main()
{
UINT32 iHorizontal = 0; //皇后位置的行号
UINT32 iVertical = 0; //皇后位置的列号

printf("请输入某皇后所在位置的行号和列号(中间用空格分隔): \n");
scanf("%d %d", &iHorizontal, &iVertical);

InitBoard(); //初始化棋盘

printf("棋盘示意图如下: \n");

FindBoard(1, iHorizontal, iVertical); //查找特定位置有皇后的所有情况,注意:第一个参数为1

printf("某皇后的行号=%d,列号=%d的情况总数为:%d.\n", iHorizontal, iVertical, g_ConditionCount);

return 0;
}

 

        与原来的代码相比,修改之后的代码有如下变化:

        第一,对原代码进行了重新排版和规范化,添加了注释,规范了变量和函数的命名,添加了更多的打印消息提示。

void find(int i)”修改为“VOID FindBoard(UINT32 iLine, UINT32 iHorizontal, UINT32 iVertical)”,添加了两个参数“iHorizontal”和“iVertical”,用于打印在某位置处有皇后的情况的总数。原代码将所有情况都打印出来了,这样不方便对输出结果进行检查。

if(check(i,j))”,这样写是不规范的。check函数的返回值为int型,而该if语句将函数的返回值当成了bool型。因此,在修改之后的代码中,将CheckBoard函数的返回值定义为bool型的,符合函数调用的规范。

       第四,在调用函数之前,要对它们进行声明,即使被调用函数的实现语句在调用函数的实现语句的前面,这也是规范性的体现。

 

       程序的执行结果如下图所示:

也来说一下八皇后问题_八皇后

 

     “他山之石,可以攻玉”,我们要不断地向他人学习,才能够及时地发现自身的不足,也才能够提升自身的能力。

 

 

 


(本人新浪微博:http://weibo.com/zhouzxi?topnav=1&wvr=5,欢迎关注!)

举报

相关推荐

回顾一下8皇后

八皇后问题

求解八皇后问题

Java 八皇后问题

算法-递归-八皇后问题

八皇后问题(回溯算法)

0 条评论