原文链接:http://blog.csdn.net/crayondeng/article/details/17174557
回溯法
回溯法有“通用的解题法”之称。用它可以系统地搜索一个问题的所有解或任一解。回溯法是一种即带有系统性又带有跳跃性的搜索算法。它在问题的解空间树中,按深度优先策略,从根节点出发搜索解空间树。算法搜索至解空间树的任一结点时,先判断该节点是否包含问题的解。如果不包含,则跳过对以该节点为根的子树的搜索,逐层向其它祖先节点回溯。否则,进入该子树,继续按照深度优先策略搜索。回溯法求问题的所有解时,要回溯到根,且根节点的所有子树都已被搜索遍才结束。回溯法求问题的一个解时,只要搜索到问题的一个解就可结束。这种以深度优先方式系统搜索问题的算法称为回溯法,它是用于解组合数大的问题。
回溯法的基本思想
确定了解空间的组织结构后,回溯法从根节点出发,以深度优先搜索方式搜索整个解空间。回溯法以这种工作方式递归地在解空间中搜索,直到找到所要求的解或解空间所有解都被遍历过为止。
回溯法搜索解空间树时,通常采用两种策略避免无效搜索,提高回溯法的搜索效率。其一是用约束函数在当前节点(扩展节点)处剪去不满足约束的子树;其二是用限界函数剪去得不到最优解的子树。这两类函数统称为剪枝函数。
回溯法解题通常包含以下三个步骤:
1.针对所给问题,定义问题的解空间;
2.确定易于搜索的解空间结构;
3.以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。
回溯法的实现
有两种方法:递归回溯和迭代回溯(非递归实现)。
下面给出这两个回溯实现的一般方法。
递归回溯:
迭代回溯:
在回溯法中有一个经典的问题:八皇后问题。
—- 以下有关八皇后问题介绍来着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个独立解,具体如下:
|
|
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
解的个数
下表给出了 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 皇后问题的解的个数。
下面正式进入编程阶段咯:
在下面的代码中给出了递归方法实现和迭代方法实现的八皇后问题!
[cpp]
view plain
copy
- #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皇后问题,通过对上面代码的稍加改动也可以实现。
运行输出结果:
[cpp]
view plain
copy
- 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个结果。