八皇后问题—经典回溯算法

八皇后问题—经典回溯算法

八皇后问题

八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。

回溯算法思想

回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。八皇后问题就是回溯算法的典型,第一步按照顺序放一个皇后,然后第二步符合要求放第2个皇后,如果没有位置符合要求,那么就要改变第一个皇后的位置,重新放第2个皇后的位置,直到找到符合条件的位置就可以了。回溯在迷宫搜索中使用很常见,就是这条路走不通,然后返回前一个路口,继续下一条路。回溯算法说白了就是穷举法。不过回溯算法使用剪枝函数,剪去一些不可能到达最终状态(即答案状态)的节点,从而减少状态空间树节点的生成。回溯法是一个既带有系统性又带有跳跃性的的搜索算法。它在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点出发搜索解空间树。算法搜索至解空间树的任一结点时,总是先判断该结点是否肯定不包含问题的解。如果肯定不包含,则跳过对以该结点为根的子树的系统搜索,逐层向其祖先结点回溯。否则,进入该子树,继续按深度优先的策略进行搜索。回溯法在用来求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。而回溯法在用来求问题的任一解时,只要搜索到问题的一个解就可以结束。这种以深度优先的方式系统地搜索问题的解的算法称为回溯法,它适用于解一些组合数较大的问题。

八皇后实现二

以下实现是极客时间王争的解法,非常巧妙,思路也非常清晰,如果理解了八皇后问题的本质后建议采用该方法,代码实现如下:

#include

int queenPlace[8] = { 8 }; //全局变量,下标表示行,值表示queen存储在那一列

int count = 0; //计数器

void printQueen() { //打印一个二维数组

for (int i = 0; i < 8; ++i) {

for (int j = 0; j < 8; ++j) {

if (queenPlace[i] == j) {

printf("Q ");

} else {

printf("* ");

}

}

printf("\n");

}

printf("----count:%d-----\n", ++count);

}

bool isOk(int row, int col) { //判断row行col列放置是否合适

int leftUp = col - 1; //左上对角线

int rightUp = col + 1; //右上对角线

for (int i = row - 1; i >= 0; --i) {

if (queenPlace[i] == col) return false; //同列上的格子有皇后

if (leftUp >= 0) {

if (queenPlace[i] == leftUp) return false; //左上对角线有皇后

}

if (rightUp < 8) {

if (queenPlace[i] == rightUp) return false; //右上对角线有皇后

}

--leftUp; ++rightUp;

}

return true;

}

void eightQueen(int row) {

if (row == 8) { //8个皇后都放置好,打印,无法递归返回

printQueen();

return;

}

for (int col = 0; col < 8; ++col) { //每一行都有8种方法

if (isOk(row, col)) { //满足要求

queenPlace[row] = col; //第row行的皇后放在col列

eightQueen(row+1); //考察下一行

}

}

}

int main() {

eightQueen(0);return 0;

}

LeetCode 51

class Solution {

public:

vector> res;

vector n_queen;

vector> solveNQueens(int n) {

n_queen.resize(n);

backtrack(0);

return res;

}

void backtrack(int row) {

if (row == n_queen.size()) {

storeResult();

return;

}

for (int i = 0; i < n_queen.size(); ++i) {

if (!isOk(row, i)) continue;

n_queen[row] = i;

backtrack(row + 1);

}

}

bool isOk(int row, int col) {

int left_up = col - 1;

int right_up = col + 1;

for (int i = row - 1; i >= 0; --i) {

if (n_queen[i] == col // 当前列

|| n_queen[i] == left_up-- // 左上对角,无需判断 left_up < 0, 该情况不会成立的

|| n_queen[i] == right_up++) { // 右上对角,无需判断 right_up > n_queen.size()

return false;

}

}

return true;

}

void storeResult() {

vector result;

for (auto i : n_queen) {

string s(n_queen.size(), '.');

s[i] = 'Q';

result.push_back(s);

}

res.push_back(result);

}

};

解法2:

class Solution {

public:

vector col;

vector dia1;

vector dia2;

vector> result;

vector generateQueen(vector& q)

{

vector res;

for (int i = 0; i < q.size(); ++i)

{

string s(q.size(), '.');

s[q[i]] = 'Q';

res.push_back(s);

}

return res;

}

void traceBack(int n, int row, vector& q)

{

if (row == n) {

result.push_back(generateQueen(q));

return;

}

for (int i = 0; i < n; ++i)

{

if (!col[i] && !dia1[row + i] && !dia2[row - i + n - 1])

{

q.push_back(i);

col[i] = true;

dia1[row + i] = true;

dia2[row - i + n - 1] = true;

traceBack(n, row + 1, q);

col[i] = false;

dia1[row + i] = false;

dia2[row - i + n - 1] = false;

q.pop_back();

}

}

}

vector> solveNQueens(int n) {

col = vector(n, false);

dia1 = vector(2 * n - 1, false);

dia2 = vector(2 * n - 1, false);

vector q;

traceBack(n, 0, q);

return result;

}

};

相关推荐

羊毛衫会缩水吗
365bet足球直播

羊毛衫会缩水吗

⌛ 08-03 👁️ 374
一代女皇减肥靠谱吗?一代女皇减肥糖真的可以瘦吗?
365bet在线足球开户

一代女皇减肥靠谱吗?一代女皇减肥糖真的可以瘦吗?

⌛ 07-01 👁️ 2552
好好用 Mac:蝶式键盘的这五年和 Mac 的一些废话
365bet足球直播

好好用 Mac:蝶式键盘的这五年和 Mac 的一些废话

⌛ 08-04 👁️ 5489
英雄联盟克隆模式哪个英雄无敌 盘点英雄联盟克隆模式最强的六位英雄
阿里云无影云手机全解析:云手机价格、使用、功能和计费详解
至强 e5620
365bet足球直播

至强 e5620

⌛ 07-28 👁️ 565