[回溯法]八皇后问题的递归与非递归算法

八皇后的问题非常有名,初次理解可能稍有难度,不过多看书,看博客和代码,几遍下来,也基本清晰。

首先不用想初始的情况,先假设前面已经排列好了几个皇后,即将排列下一个皇后。依次遍历八个位置,然后与之前的进行判断这个位置是否可行,如可行则进行下一个皇后,否则则移动位置继续判断。很简单。但是有两个个问题:

1、不全,某个位置有八种方法排列,你只用了一种,当然你可以每个位置遍历,但太耗时,回溯法可以解决很大的一部分问题,即当你在对某一行皇后进行放置时,如果一直放不好(到最后),那后面的行就不需要再遍历了,直接回溯上一行,将上一行的位置后移——依次进行这个步骤,直到第一行,遍历结束。
2、如何判定当前位置合法?首先,两个皇后不能同一列(这里要注意,算法的遍历次序是按行来的,所以不必考虑行的情况),其次,不能斜对角。
代码如下,很清晰:

#define N 8
/* Place(),第一个参数表示八皇后的列位置,第二个表示当前要插入的八皇后的行数。 */
bool Place(int eightqueen[],int k)
{
    int i = 0;
    while(i<k)
    {
        if(eightqueen[i] == eightqueen[k] || abs(eightqueen[i] - eightqueen[k]) == abs(i- k))
        {
            return false;
        }
        i++;
    }
    return true;
}

行是从0开始,而列是从1开始。

1、递归解法

int eight_queen[N] = {0};
int gcount = 0;

void Eight_Queen_Recursion(int eight_queen[],int i)
{
    eight_queen[i]++;
    while(!Place(eight_queen,i) && eight_queen[i]<=N)
    {
        eight_queen[i] ++;
    }
    if(eight_queen[i] <= N)
    {
        if(i == N -1 )
        {
            gcount ++;
        }
        else
        {
            i++;
            eight_queen[i] = 0;
        }
        Eight_Queen_Recursion(eight_queen,i);
    }
    else
    {
        i--;
        if(i<0)
        {
            return;
        }
        Eight_Queen_Recursion(eight_queen,i);
    }

}
void main()
{
    Eight_Queen_Recursion(eight_queen,0);
    cout<<gcount<<endl;
}

2、非递归解法

void Eight_Queen()
{
    int eight_queen[N] = {0};       //初始化八皇后的列。每一行的八皇后所在的列
    int i = 0;
    int count = 0;
    while(i>=0)
    {
        eight_queen[i]++;   //从1开始
        while(!Place(eight_queen,i) && eight_queen[i] <= N) //判断此列是否符合条件。
        {
            eight_queen[i] ++;  //将列位置后移
        }
        if(eight_queen[i] <= N)
        {
            //找到一个位置
            if(i == N-1)
            {
                //这是一个解
                count ++;
            }
            else
            {
                //没有到最后一行,则进行下一行
                i++;
                eight_queen[i] = 0; //下一列从0开始
            }
        }
        else//如果这一行到最后也没有找到合适的列,则回溯上一行。
        {
            i--;
        }
    }
    cout<<count<<endl;
}
void main()
{
    Eight_Queen();
}

将Place函数与下面的结合,即是完整的程序。

点赞