也来说一下八皇后问题

       (本文的所有代码均是基于此文:http://blog.csdn.net/mbh_1991/article/details/23869459,感谢博主的贡献!)

 

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

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

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

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

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

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

/**********************************************************************

*版权所有 (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型的,符合函数调用的规范。

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

 

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

也来说一下八皇后问题_第1张图片

 

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

 

 

 

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

你可能感兴趣的:(也来说一下八皇后问题)