題目說明:
西洋棋中的皇后可以直線前進,吃掉遇到的所有棋子,如果棋盤上有八個皇后,則這八個皇后如何相安無事的放置在棋盤上,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 << "\nNO " << ++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皇后,如果要計算任意皇后,需要增加變量,會帶來額外的系統開銷和編程難度。