回溯——八皇后
题意解析
八皇后问题 (英文:Eight
queens),是由国际西洋棋棋手马克斯·贝瑟尔于1848年提出的问题,是==回溯算法==的典型案例。
问题表述为:在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。如果经过±90度、±180度旋转,和对角线对称变换的摆法看成一类,共有42类。计算机发明后,有多种计算机语言可以编程解决此问题。
解题思路
二、如何解决八皇后问题?
所谓递归回溯,本质上是一种枚举法。(我们更愿意称之为“有技巧的枚举”)这种方法从棋盘的第一行开始尝试摆放第一个皇后,摆放成功后,递归一层,再遵循规则在棋盘第二行来摆放第二个皇后。如果当前位置无法摆放,则向右移动一格再次尝试,如果摆放成功,则继续递归一层,摆放第三个皇后......
如果某一层看遍了所有格子,都无法成功摆放,则回溯到上一个皇后,让上一个皇后右移一格,再进行递归。如果八个皇后都摆放完毕且符合规则,那么就得到了其中一种正确的解法。说起来有些抽象,我们来看一看递归回溯的详细过程。
1.第一层 递归,尝试在第一行 摆放第一个皇后 :
img
2.第二层 递归,尝试在第二行 摆放第二个皇后 (前两格被第一个皇后封锁,只能落在第三格):
img
3.第三层 递归,尝试在第三行 摆放第三个皇后 (前四格被第一第二个皇后封锁,只能落在第五格):
img
4.第四层 递归,尝试在第四行 摆放第四个皇后 (第一格被第二个皇后封锁,只能落在第二格):
img
5.第五层 递归,尝试在第五行 摆放第五个皇后 (前三格被前面的皇后封锁,只能落在第四格):
img
6.由于所有格子都“绿了”,第六行已经没办法摆放皇后,于是进行回溯,重新摆放第五个皇后 到第八格 。:
img
7.第六行仍然没有办法摆放皇后,第五行也已经尝试遍了,于是回溯到第四行 ,重新摆放第四个皇后 到第七格 。:
img
8.继续摆放第五个皇后,以此类推......
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <iostream> using namespace std;const int ArSize = 8 ;int num = 0 ;void solve (bool arr[ArSize][ArSize], int row) ;bool check (bool arr[ArSize][ArSize], int row, int column) ;void outPut (bool arr[ArSize][ArSize]) ;int main () { bool chessboard[ArSize][ArSize]; for (auto &i : chessboard) { for (auto &j : i) { j = false ; } } solve (chessboard, 0 ); cout << "八皇后问题共有" << num << "种解!" << endl; system ("pause" ); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 void solve (bool arr[ArSize][ArSize], int row) { for (int column = 0 ; column < ArSize; ++column) { arr[row][column] = true ; if (check (arr, row, column)) { if (row + 1 == ArSize) { outPut (arr); } else { solve (arr, row + 1 ); } } arr[row][column] = false ; } }bool check (bool arr[ArSize][ArSize], int row, int column) { if (row == 0 ) { return true ; } int i, j; for (i = 0 ; i < row; ++i) { if (arr[i][column]) { return false ; } } i = row - 1 ; j = column - 1 ; while (i >= 0 && j >= 0 ) { if (arr[i][j]) { return false ; } --i; --j; } i = row - 1 ; j = column + 1 ; while (i >= 0 && j <= ArSize - 1 ) { if (arr[i][j]) { return false ; } --i; ++j; } return true ; }void outPut (bool arr[ArSize][ArSize]) { ++num; cout << "**********************" << num << "*********************" << endl; for (int i = 0 ; i < ArSize; ++i) { for (int j = 0 ; j < ArSize; ++j) { cout << arr[i][j] << " " ; } cout << endl; } cout << "*********************************************" << endl; }
参考资料
[1]https://www.cnblogs.com/smile233/p/8483729.html
[2]https://baike.baidu.com/item/%E5%85%AB%E7%9A%87%E5%90%8E%E9%97%AE%E9%A2%98