演算法之n皇后問題
阿新 • • 發佈:2018-12-18
1. 問題描述:在n×n的棋盤上放置彼此不受攻擊的n個皇后。按照國際象棋的規則,皇后可以攻擊與之處在同一行或同一列或同一斜線上的棋子。n皇后問題等價於在n×n的棋盤上放置n個皇后,任何2個皇后不能放在同一行或同一列或同一斜線上。
2. 問題分析:
用n元陣列x[n]表示問題的解。其中x[i]表示皇后i放在棋盤第i行第x[i]列。由於不允許將2個皇后放在同一列上,所以解向量中的x[i]互不相同,
2個皇后不能放在同一斜線上是問題的隱約束。設2個皇后的放置位置分別是(i,j)和(k,l),則如果滿足|i-k|=|j-l|,就表明2個皇后位於同一條斜線上。
分析可知,解空間樹是完全
n叉樹,剪枝函式剪去不滿足行、列、斜線約束的子樹。#include <iostream> #include <cmath> using namespace std; int N=5; int x[5]; //可行解 int sum=0;//可行解數量 bool Place(int k) { for(int i=0; i<k; i++) { if(abs(k-i)==abs(x[i]-x[k])||x[i]==x[k])return false; } return true; } void Backtrack(int t) //遞歸回溯 { if(t>=N) { sum++;//到達葉子結點,即找到了一個新的可行解,則解的數量sum++; for(int i=0; i<N; i++) { cout<<x[i]<<" "; } cout<<endl; } else { for(int i=0; i<N; i++) { x[t]=i; if(Place(t))Backtrack(t+1); } } } void Backtrack2() //迭代回溯 { x[0]=0; int k=0; while(k>=0) { while(x[k]<N&&Place(k)==false)x[k]+=1; if(x[k]<N) { if(k==N-1) //到了葉子結點,輸出一個解,回溯 { sum++; for(int i=0; i<N; i++) { cout<<x[i]<<" "; } cout<<endl; k--; x[k]+=1; } else //沒到葉子結點繼續往下走 { k++; x[k]=0; } } else //說明當前行無法放置,回溯 { k--; x[k]+=1; } } } int main() { //Backtrack(0); Backtrack2(); /*0 2 4 1 3 0 3 1 4 2 1 3 0 2 4 1 4 2 0 3 2 0 3 1 4 2 4 1 3 0 3 0 2 4 1 3 1 4 2 0 4 1 3 0 2 4 2 0 3 1*/ }
3.時間複雜度:最壞時間複雜度Place方法O(n),所以Backtrack方法時間複雜度為O(n^3);