1 问题
要在8*8的国际象棋棋盘中放8个皇后,使任意两个皇后都不能互相吃掉。规则是皇后能吃掉同一行、同一列、同一对角线的棋子。有多少种摆放方法?
2 缘由
八皇后问题有很多解题思路,包括递归式和迭代式。
无论是网上资源,还是面试书籍,往往只给出关键的算法步骤。
面试时,面试官往往希望能手写一个完整的版本。
例如, 选择迭代方法,必须先考虑是否使用辅助栈?该辅助栈是使用STL版本stack, 还是你自己手写一个栈?
难点是,现场面对面试官,我们能否真的很好地设计一个完备的辅助栈?
在面试时,我比较推荐使用STL的容器,简单方便。
如果这些容器不符合你的需求,可以在STL容器基础上扩建。
例如,解决八皇后问题使用的辅助栈,它实际既需要可以遍历,也需要pop()时候返回栈顶元素。
STL的stack无法满足,需要在其基础上扩展。
3 扩展功能的stack
#pragma once
#include <vector>
using namespace std;
template <typename T, class Container = std::vector<T> >
class Stack {
private:
Container _data;
public:
void push(T const& e) {
_data.insert(_data.end(), e);
}
T pop() {
T tmp = _data[_data.size() - 1];
_data.pop_back();
return tmp;
}
//e首次出现的索引
int find(T e);
void traverse(void (*)(T&));
int size() { return _data.size(); }
};
template <typename T, class Container>
int Stack<T, Container>::find(T e) {
int index = -1;
typename std::vector<T>::iterator it = std::find(_data.begin(), _data.end(), e);
if (it != _data.end()) {
index = it - _data.begin();
}
return index;
}
template <typename T, class Container>
void Stack<T, Container>::traverse(void (*visit)(T&)) {
for (auto i : _data) {
visit(i);
}
}
4 支持判等的皇后类
#pragma once
/*
--------------->y
│
│
│
│
↓
x
*/
//皇后类
class Queen {
public:
int x, y; //皇后在棋盘上的位置坐标
public:
Queen(int tmpx = 0, int tmpy = 0) : x(tmpx), y(tmpy) {
}
Queen(Queen const& tmpQ) : x(tmpQ.x), y(tmpQ.y) {
}
bool operator== (Queen const& q) const {
if ( (x == q.x) //列冲突
|| (y == q.y) //行冲突
|| (x + y == q.x + q.y) //对角线
|| (x - y == q.x - q.y) ) {
return true;
}
return false;
}
bool operator!= (Queen const& q) const {
return !(*this == q);
}
};
5 关键步骤
//N皇后问题
void n_queen_question(int N) {
Stack<Queen> solu;
Queen q(0, 0); // 从原点出发试探
while( !(q.x == 0 && q.y >= N) ) { // 试探结束条件 q.x == 0 && q.y >= N
//判断是否已出边界
if ( N <= solu.size() || q.y >= N) {
q = solu.pop();
q.y++; // 此时可能会出现q.x = 0 && q.y >= N 情况,故需要再次判断是否满足第一个while条件
} else {
while( (q.y < N) && (0 <= solu.find(q)) ) {
q.y++;
nCheck++;
}
if (q.y < N) {
solu.push(q);
if (N <= solu.size()) {
nSolu++;
//打印该次输出结果
displayProgress ( solu, N );
}
q.x++;
q.y = 0;
}
}
if ( Step == runMode ) {
displayProgress ( solu, N );
}
}
}
上面完整代码已经上传到github。
参考文献
- 邓俊辉.<数据结构>.第4.4.2节
- 可遍历的栈Stack