文章目录
- 题目描述
- 思路分析
- 回顾回溯法的基本框架
- 解题框架应用到本题
- 定义问题的解空间
- 定义约束函数
- 模仿回溯法的框架去解决问题
- 实现源码
- 分析与总结
题目描述
- 在8×8格的棋盘上放置彼此不受攻击的8个皇后。国际象棋的规则:皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子

思路分析
- 八皇后问题等价于,在8*8格的棋盘上放置8个皇后, 任何两个皇后皇后不得在同一行或者同一列或者同一斜线上
回顾回溯法的基本框架
- 首先定义问题的解空间:给出问题的所有解和最优解。在我理解,就是给出将问题使用另外一种可编程的形式表达出来。
- 确定易于搜索的解空间结构:
- 两种树型结构:
- 子集树:问题是从n个元素的集合中找出满足性质的k个元素的集合,是组合问题
- 排列树:确定n个元素的满足某种性质的排列,使用排列树。
- 确定约束函数,两种方式,一种是约束函数,另外一种是限界函数
- 约束函数,在扩展结点处减去不满足约束的子树。
- 限界函数,减去得不到最优解的子树。
- 从根节点出发,以深度优先的方式搜索解空间树,算法搜索到空间树的任意一点。
解题框架应用到本题
定义问题的解空间
- 定义解空间,使用可编程形式去定义问题。将问题转换成的一维数组去表示,值表示对应的列,位序表示行!


- 如果我没有看过课本,我会默认使用二维数组去解决这个问题,而不是一位数组,如果使用二维数组会遇到很多的问题。
定义约束函数

模仿回溯法的框架去解决问题
void backtrack(int t)
{if (t>n) output(x);elsefor (int i=f(n,t);i<=g(n,t);i++) {x[t]=h(i);if (constraint(t)&&bound(t)) backtrack(t+1);}
}
- t表示递归深度,n表示最大递归深度,这也是控制层数
- output(x):表示输出可行解x
- for循环遍历起始点和终止点
- 只有符合约束条件,才会进行下一步迭代
实现源码
#include<iostream>using namespace std;
int queen[9];
int total = 0;
bool constrain(int row) {for (int i = 1; i < row; ++i){if (queen[i] == queen[row] || abs(row - i) == abs(queen[row] - queen[i])){return false;}}return true;
}
void recursive(int row) {for (int i = 1; i < 9; i++) {cout << queen[i] << " ";}cout << endl;if (row == 9){total++;}else {for (int col = 1; col < 9; ++col){queen[row] = col;if (constrain(row)){recursive(row + 1);}}}
}int main(int argc, char const* argv[])
{recursive(1);cout << total << endl;int a;cin >> a;return 0;
}
分析与总结
- 这是回溯算法一个简单的应用,是一个很好的尝试!回溯算法还是很普适的!