回溯法 之 八皇后问题

回溯法

回溯法有“通用的解题法”之称。用它可以系统地搜索一个问题的所有解或任一解。回溯法是一种即带有系统性又带有跳跃性的搜索算法。它在问题的解空间树中,按深度优先策略,从根节点出发搜索解空间树。算法搜索至解空间树的任一结点时,先判断该节点是否包含问题的解。如果不包含,则跳过对以该节点为根的子树的搜索,逐层向其它祖先节点回溯。否则,进入该子树,继续按照深度优先策略搜索。回溯法求问题的所有解时,要回溯到根,且根节点的所有子树都已被搜索遍才结束。回溯法求问题的一个解时,只要搜索到问题的一个解就可结束。这种以深度优先方式系统搜索问题的算法称为回溯法,它是用于解组合数大的问题。

回溯法的基本思想

确定了解空间的组织结构后,回溯法从根节点出发,以深度优先搜索方式搜索整个解空间。回溯法以这种工作方式递归地在解空间中搜索,直到找到所要求的解或解空间所有解都被遍历过为止。
回溯法搜索解空间树时,通常采用两种策略避免无效搜索,提高回溯法的搜索效率。其一是用约束函数在当前节点(扩展节点)处剪去不满足约束的子树;其二是用限界函数剪去得不到最优解的子树。这两类函数统称为剪枝函数。

回溯法解题通常包含以下三个步骤:

1.针对所给问题,定义问题的解空间;
2.确定易于搜索的解空间结构;
3.以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。


回溯法的实现

有两种方法:递归回溯和迭代回溯(非递归实现)
下面给出这两个回溯实现的一般方法。

递归回溯:

回溯法 之 八皇后问题_第1张图片

迭代回溯:

回溯法 之 八皇后问题_第2张图片


在回溯法中有一个经典的问题八皇后问题

---- 以下有关八皇后问题介绍来着wikipedia。

八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n当且仅当 n = 1 或 n ≥ 4 时问题有解

历史

八皇后问题最早是由国际西洋棋棋手马克斯·贝瑟尔于1848年提出。之后陆续有数学家对其进行研究,其中包括高斯和康托,并且将其推广为更一般的n皇后摆放问题。八皇后问题的第一个解是在1850年由弗朗兹·诺克给出的。诺克也是首先将问题推广到更一般的n皇后摆放问题的人之一。1874年,S.冈德尔提出了一个通过行列式来求解的方法,这个方法后来又被J.W.L.格莱舍加以改进。

艾兹格·迪杰斯特拉在1972年用这个问题为例来说明他所谓结构性编程的能力[2]

八皇后问题在1990年代初期的著名电子游戏第七访客和NDS平台的著名电子游戏雷顿教授与不可思议的小镇中都有出现。

八皇后问题的解

八皇后问题一共有 92 个互不相同的解。如果将旋转和对称的解归为一种的话,则一共有12个独立解,具体如下:

独立解1
独立解2
独立解3
独立解4
独立解5
独立解6
独立解7
独立解8
独立解9
独立解10
独立解11
独立解12

解的个数

下表给出了 n 皇后问题的解的个数包括独立解U(OEIS中的数列A002562)以及互不相同的解D(OEIS中的数列A000170)的个数:

n 1 2 3 4 5 6 7 8 9 10 11 12 13 14 .. 24 25 26
U: 1 0 0 1 2 1 6 12 46 92 341 1,787 9,233 45,752 .. 28,439,272,956,934 275,986,683,743,434 2,789,712,466,510,289
D: 1 0 0 2 10 4 40 92 352 724 2,680 14,200 73,712 365,596 .. 227,514,171,973,736 2,207,893,435,808,352 22,317,699,616,364,044

可以注意到六皇后问题的解的个数比五皇后问题的解的个数要少。现在还没有已知公式可以对 n 计算 n 皇后问题的解的个数。



下面正式进入编程阶段咯:

在下面的代码中给出了递归方法实现和迭代方法实现的八皇后问题!

#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;

int queen[9];

//数组初始化
void init()
{
    memset(queen,0,9*sizeof(int));
}

//输出结果
void print()
{
    for(int i=1; i<9; i++) cout<<queen[i]<<"  ";
    cout<<endl;
}

//剪枝函数
bool canPlaceQueen(int k)
{
    for(int i = 1; i < k; i++)
    {
        //判断是否处于同一列或同一斜线
        if(queen[i] == queen[k] || abs(k-i) == abs(queen[k]-queen[i])) return false;
    }
    return true;
}
//迭代方法求解八皇后过程
void eightQueen_1()
{
    int k = 1;
    while(k>=1)
    {
        while(queen[k]<=7)
        {
            queen[k] += 1;
            if(k == 8 && canPlaceQueen(k))
            {
                print();
            }
            else if(canPlaceQueen(k))
            {
                k++;
            }
        }
        queen[k] = 0;
        k--;
    }
}

//递归方法求解八皇后过程
void eightQueen_2(int k)
{
    for(int i=1; i<9; i++)
    {
        queen[k] = i;
        if(k == 8 && canPlaceQueen(k))
        {
            print();
            return;
        }
        else if(canPlaceQueen(k))
        {
            eightQueen_2(k+1);
        }
    }
}
int main()
{
    init();
    eightQueen_1();
//    eightQueen_2(1);
    return 0;
}

过程比较简单,就不多细说了,关于n皇后问题,通过对上面代码的稍加改动也可以实现。

运行输出结果:
1  5  8  6  3  7  2  4
1  6  8  3  7  4  2  5
1  7  4  6  8  2  5  3
1  7  5  8  2  4  6  3
2  4  6  8  3  1  7  5
2  5  7  1  3  8  6  4
2  5  7  4  1  8  6  3
2  6  1  7  4  8  3  5
2  6  8  3  1  4  7  5
2  7  3  6  8  5  1  4
2  7  5  8  1  4  6  3
2  8  6  1  3  5  7  4
3  1  7  5  8  2  4  6
3  5  2  8  1  7  4  6
3  5  2  8  6  4  7  1
3  5  7  1  4  2  8  6
3  5  8  4  1  7  2  6
3  6  2  5  8  1  7  4
3  6  2  7  1  4  8  5
3  6  2  7  5  1  8  4
3  6  4  1  8  5  7  2
3  6  4  2  8  5  7  1
3  6  8  1  4  7  5  2
3  6  8  1  5  7  2  4
3  6  8  2  4  1  7  5
3  7  2  8  5  1  4  6
3  7  2  8  6  4  1  5
3  8  4  7  1  6  2  5
4  1  5  8  2  7  3  6
4  1  5  8  6  3  7  2
4  2  5  8  6  1  3  7
4  2  7  3  6  8  1  5
4  2  7  3  6  8  5  1
4  2  7  5  1  8  6  3
4  2  8  5  7  1  3  6
4  2  8  6  1  3  5  7
4  6  1  5  2  8  3  7
4  6  8  2  7  1  3  5
4  6  8  3  1  7  5  2
4  7  1  8  5  2  6  3
4  7  3  8  2  5  1  6
4  7  5  2  6  1  3  8
4  7  5  3  1  6  8  2
4  8  1  3  6  2  7  5
4  8  1  5  7  2  6  3
4  8  5  3  1  7  2  6
5  1  4  6  8  2  7  3
5  1  8  4  2  7  3  6
5  1  8  6  3  7  2  4
5  2  4  6  8  3  1  7
5  2  4  7  3  8  6  1
5  2  6  1  7  4  8  3
5  2  8  1  4  7  3  6
5  3  1  6  8  2  4  7
5  3  1  7  2  8  6  4
5  3  8  4  7  1  6  2
5  7  1  3  8  6  4  2
5  7  1  4  2  8  6  3
5  7  2  4  8  1  3  6
5  7  2  6  3  1  4  8
5  7  2  6  3  1  8  4
5  7  4  1  3  8  6  2
5  8  4  1  3  6  2  7
5  8  4  1  7  2  6  3
6  1  5  2  8  3  7  4
6  2  7  1  3  5  8  4
6  2  7  1  4  8  5  3
6  3  1  7  5  8  2  4
6  3  1  8  4  2  7  5
6  3  1  8  5  2  4  7
6  3  5  7  1  4  2  8
6  3  5  8  1  4  2  7
6  3  7  2  4  8  1  5
6  3  7  2  8  5  1  4
6  3  7  4  1  8  2  5
6  4  1  5  8  2  7  3
6  4  2  8  5  7  1  3
6  4  7  1  3  5  2  8
6  4  7  1  8  2  5  3
6  8  2  4  1  7  5  3
7  1  3  8  6  4  2  5
7  2  4  1  8  5  3  6
7  2  6  3  1  4  8  5
7  3  1  6  8  5  2  4
7  3  8  2  5  1  6  4
7  4  2  5  8  1  3  6
7  4  2  8  6  1  3  5
7  5  3  1  6  8  2  4
8  2  4  1  7  5  3  6
8  2  5  3  1  7  4  6
8  3  1  6  2  5  7  4
8  4  1  3  6  2  7  5

上面一共输出的是92个结果。



你可能感兴趣的:(C++,回溯法,八皇后问题)