八皇后问题递归回溯算法实现


/*
 * 八皇后问题递归回溯算法实现
 *
 * 八皇后问题或N皇后问题描述为:
 * 求解如何在N*N的棋盘上无冲突地排放N个皇后棋子。其中,皇后的移动方式规定为水平、竖直及45°斜线方向。因此,在任意一个皇后所在位置的水平、竖直和45°方向上都不能出现其他的皇后棋子。
 *
 * 回溯法的基本思想是:在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一个结点时,要先判断该结点是否包含问题的解,如果包含,就从该节点出发继续探索下去;如果该结点不包含问题的解,那就说明以该结点为根结点的子树一定不包含问题的最终解,因此要跳过对以该节点为根的子树的系统探索,逐层向其祖先结点回溯。这个过程又叫做解空间树的剪枝操作。
 *
 * 八皇后问题可以有很多解法,其中之一是回溯法。
 * 用回溯法求解八皇后问题,可以按列试探可能的解,一旦该列找不到任何可能的解那么就要向后回溯。
 */

/*程序代码如下:*/

#include <stdio.h>
#define NUM 8

/*棋盘用NUM*NUM的矩阵Q描述,其中,里面的元素如果是1表示可以放置皇后,如果为0表示不能放置皇后,另外,(i,j)表示矩阵的第(i,j)个元素*/

/*判断能否在(i,j)位置放置皇后*/
int isOK(int i, int j, int (*Q)[NUM])
{
    int s=0, t=0;
    for(s=i,t=0;t<NUM;++t)      /*判断行*/
        if(t!=j && Q[s][t]==1)
            return 0;
    for(s=0,t=j;s<NUM;++s)      /*判断列*/
        if(s!=i && Q[s][t]==1)
            return 0;
    for(s=i-1,t=j-1;s>=0&&t>=0;--s,--t)   /*判断左上方*/
        if(Q[s][t]==1)
            return 0;
    for(s=i+1,t=j-1;s<NUM&&t>=0;++s,--t)   /*判断左下方*/
        if(Q[s][t]==1)
            return 0;

/* Thank @ewitt*/
/* 下面的东西没用 */
/*    for(s=i-1,t=j+1;s>=0&&t<NUM;--s,++t)   //判断右上方
 *      if(Q[s][t]==1)
 *          return 0;
 *  for(s=i+1,t=j+1;s<NUM&&t<NUM;++s,++t)   //判断右下方
 *      if(Q[s][t]==1)
 *          return 0;

*/
    return 1;
}

void Queen(int j, int (*Q)[NUM])
{
    if(j==NUM)      /*找到一个解*/
    {
        for(int i=0;i<NUM;++i)
        {
            for(int k=0;k<NUM;++k)
                printf("%d ",Q[i][k]);
            printf("\n");
        }
        printf("\n");
        return;
    }
    else{

        for(int i=0;i<NUM;++i)
        {
            if(isOK(i,j,Q))     /*如果可以*/
            {
                Q[i][j]=1;
                Queen(j+1,Q);   /*深度优先探索解空间树*/
                Q[i][j]=0;
            }
        }
    }
}


/*test program*/
int main()
{
    int Q[NUM][NUM];
    int i=0, j=0;
    for(i=0;i<NUM;++i)
        for(j=0;j<NUM;++j)
            Q[i][j] = 0;   /*初始化*/

    Queen(0,Q);

    return 0;
}