题目说明:
西洋棋中的皇后可以直线前进,吃掉遇到的所有棋子,如果棋盘上有八个皇后,则这八个皇后如何相安无事的放置在棋盘上,1970年
与1971年,E.W.Dijkstra与N.Wirth曾经用这个问题来讲解程式设计之技巧。
题目解析:
关于棋盘的问题,都可以用递回求解,然而如何减少递回的次数?在八个皇后的问题中,不必要所有的格子都检查过,例如若某列检查
过,该该列的其它格子就不用再检查了,这个方法称为分支修剪。
程序代码:
#include<iostream> using namespace std; const int N_SIZE = 8; /// 使用数组记录状态 int UpperOblique[2*N_SIZE + 1] = {0}; int LowerOblique[2*N_SIZE + 1] = {0}; int Column[N_SIZE + 1] = {0}; int Queen[N_SIZE + 1] = {0}; int Number = 0; void ShowResult() { cout << " NO " << ++Number << ":" <<endl; for (int i=1; i<=N_SIZE; ++i) { for (int j=1; j<=N_SIZE; ++j) { if (Queen[i]==j) { cout << "Q"; } else { cout << " ."; } } cout << endl; } } void BlackTrack(int i) { if (i > N_SIZE) ShowResult(); else { for (int j=1; j<=N_SIZE; ++j) { if (Column[j]==0 && UpperOblique[i-j+N_SIZE]==0 && LowerOblique[i+j]==0) { Queen[i] = j; Column[j] = UpperOblique[i-j+N_SIZE]=LowerOblique[i+j]=1; BlackTrack(i+1); Column[j] = UpperOblique[i-j+N_SIZE]=LowerOblique[i+j]=0; } } } } int main() { BlackTrack(1); return 0; }
#include <iostream> #include <stdlib.h> using namespace std; const int N_SIZE = 8; int Record[N_SIZE+1] = {0}; /// 记录每列选择的位置 int ResultNum = 0; bool Check(int x) { for (int i = 1; i<x; i++) { if ((Record[i]==Record[x]) || (abs(Record[i]-Record[x]) == abs(i-x))) { return false; } } return true; } void ShowResult() { cout << "No. " << ++ResultNum <<endl; for (int i=1; i<=N_SIZE; ++i) { for (int j=1; j<=N_SIZE; ++j) { if (Record[i]==j) { cout << "1 "; } else { cout << "0 "; } } cout << endl; } } void BackTrack(int x) { if (x > N_SIZE) { ShowResult(); } else { for (int j=1; j <=N_SIZE; ++j) { Record[x] = j; if (Check(x)) { BackTrack(x+1); } } } } int main() { BackTrack(1); return 0; }
还有诸如 遗传算法、退火算法、位运算和基于Q一矩阵的快速搜索算法。但是这些算法中,遗传算法和基于Q一矩阵的快速搜索算法一般只能得到部分解;退火算法得到的解往往是近似解,存在一定的误差:位运算依赖硬件,32位机器只能计算32皇后,如果要计算任意皇后,需要增加变量,会带来额外的系统开销和编程难度。