問題描述:ios
在n*n的棋盤上放置彼此不受攻擊的n個皇后。按國際象棋的規則,皇后能夠與之處在同一行或者同一列或同一斜線上的棋子。算法
n後問題等價於在n*n格的棋盤上放置n皇后,任何2個皇后不放在同一行或同一列的斜線上。數組
算法設計:函數
|i-k|=|j-l|成立,就說明2個皇后在同一條斜線上。能夠設計一個place函數,測試是否知足這個條件。測試
1 當i>n時,算法搜索至葉節點,獲得一個新的n皇后互不攻擊放置方案,當前已找到的可行方案sum加1.spa
2 當i<=n時,當前擴展結點Z是解空間中的內部結點。該結點有x[i]=1,2,3....n共n個兒子節點。設計
對當前擴展結點Z的每一個兒子節點,由place檢察其可行性。並以深度優先的方式遞歸地對可行子樹,或剪去不可行子樹。code
算法描述: blog
#include <iostream> #include <cstdlib> using namespace std; class Queen{ friend int nQueen(int); private: bool Place(int k); void Backtrack(int t); int n, * x; long sum; }; bool Queen::Place(int k) { for(int j=1;j<k;j++) if((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k])) return false; return true; } void Queen::Backtrack(int t) { if(t>n) sum++; else for(int i=1;i<=n;i++) { x[t] = i; if(Place(t)) Backtrack(t+1); } } int nQueen(int n) { Queen X; X.n = n; X.sum = 0; int *p = new int [n+1]; for(int i=0;i<=n;i++) p[i] = 0; X.x = p; X.Backtrack(1); delete [] p; cout<<X.sum<<endl; return X.sum; } int main() { nQueen(4); nQueen(2); nQueen(3); return 0; }
執行結果:遞歸
迭代回溯:
數組x記錄瞭解空間樹中從根到當前擴展結點的路徑,這些信息已包含了回溯法在回溯時所須要的信息。利用數組x所含的信息,可將上述回溯法表示成非遞歸形式,進一步省去O(n)遞歸棧空間。
n後問題的非遞歸迭代回溯法Backtrack可描述以下:
#include <iostream> #include <cstdlib> using namespace std; class Queen{ friend int nQueen(int); private: bool Place(int k); void Backtrack(void);//......... int n, * x; long sum; }; bool Queen::Place(int k) { for(int j=1;j<k;j++) if( ( abs(k-j) == abs(x[j]-x[k]) ) ||( x[j] == x[k] ) ) return false; return true; } void Queen::Backtrack(void)//...... { x[1] = 0; int k = 1; while(k>0) { x[k]+=1; while( (x[k]<=n) && !(Place(k)) )//k還不是最後的葉子結點,且位置沒有衝突 x[k] += 1; if(x[k] <= n) if(k == n)//k是葉子結點 sum++; else { k++; x[k] = 0; } else k--; } } int nQueen(int n) { Queen X; X.n = n; X.sum = 0; int *p = new int [n+1]; for(int i=0;i<=n;i++) p[i] = 0; X.x = p; X.Backtrack();//...... delete [] p; cout<<X.sum<<endl; return X.sum; } int main() { nQueen(4); nQueen(2); nQueen(3); return 0; }
執行結果: