用棧實現八皇后問題
阿新 • • 發佈:2019-02-08
國際象棋中皇后勢力的範圍是其所在位置的水平線、垂直線以及兩條對角線。就像下面這樣
其中的 9 就表示皇后,其中的 1 表示皇后的勢力範圍。於是就產生了一個問題,在 n * n 的一個棋盤上,最多隻能放置 n 個皇后使得他們不能互相攻擊。解決這個問題的方式可以為先放置一個皇后在(0,0)處,之後在下一排下一位放置下一個皇后,不行的話再向後挪一位,然後再向下一排放置下一個皇后,但是當某一排皇后找不到合適位置時,就回到上一排,再挪動上一個皇后,一直到 n 個皇后放置完。這其中最主要的就是遞迴的呼叫以及棧的特性的使用。具體實現程式碼如下:
// ConsoleApplication1.cpp : 定義控制檯應用程式的入口點。 // #include "stdafx.h" #include <iostream> #include<cmath> using namespace std; #define StackSize 8 /*最多放8個皇后*/ int queen[StackSize][StackSize] = { 0 }; /*棋盤*/ int ans = 0; /*解數*/ int top = -1; /*棧頂指標*/ int datas[8]; /*儲存皇后位置*/ /*入棧*/ void Push(int x) //入棧操作 { top++; //棧頂指標上移 datas[top] = x; } /*出棧*/ void Pop() //出棧操作 { top--; //棧頂指標下移 } void SeqStack() { top = -1; } //建構函式,初始化空棧 /*放N皇后的遞迴函式*/ void PlaceQueen(int row) //在棧頂放置符合條件的值的操作,即擺放皇后 { bool Judgement(); void SeqStack(); //關鍵點1:每一次擺放都會初始化空棧 void Output(); for (int col = 0; col<StackSize; col++) //窮盡0~7,即窮盡列 { Push(col); if (Judgement()) //判斷擺放皇后的位置是否安全 { if (row<StackSize - 1) //若還沒有放到第八個皇后,則進行下一個皇后的放置 PlaceQueen(row + 1); else { ans++; //解數加1 Output(); //列印成功的棋盤 } } Pop(); //若不符合條件則出棧 } } /*關鍵點2:判斷合法性*/ bool Judgement() { for (int i = 0; i<top; i++) //依次檢查前面各行的皇后位置 if (datas[top] == datas[i] || (abs(datas[top] - datas[i])) == (top - i)) //判斷是否在同一列同一斜線 return false; /*第一個條件,使每次入棧的數字不同層(行)*/ return true; /*top-i的值就是皇后之間的非法相對距離,值為0、1、2....,也就是同一條對角線或者斜對角線。data[top]-data[i]為2個皇后的實際的相對距離。*/ } /*輸出棋盤*/ void Output() //將棧的陣列形式列印成棋盤形式 { cout << "NO." << ans << ":" << endl; for (int i = 0; i<StackSize; i++) { for (int j = 0; j<datas[i]; j++) cout << "- "; //不放置處列印“-” cout << "Q"; //放置處列印“Q” for (int j = StackSize - 1; j>datas[i]; j--) cout << " -"; cout << endl; //換行 } cout << endl; } int main() { PlaceQueen(0); //從棧底開始賦值 cout << "the total number of solutions is:" << ans << endl; //輸出擺放方法的總數 system("pause"); return 0; }
我自己試著用棧再寫了一下,但是主要還是借鑑了大佬,在此表示感謝。
另外大佬的原始碼在VS2015上會報錯,“data 不明確的符號”,我查了一下是因為在VS的函式庫中有 data ,所以編譯器會不確定我們所寫的data是庫中的data還是定義的全域性變數,所以就報錯了。解決辦法就是用::來表明使用的是庫函式,當然更簡單的就是直接改個變數名。