說起八皇后,其實這是一個古老而著名的問題。該問題是19世紀著名的數學家高斯1850年提出:在一個8*8國際象棋盤上,有8個皇后,每個皇后佔一格;要求皇后之間不會出現相互“攻擊”的現象,即不能有兩個皇后處在同一行、同一列或同一對角線上。問共有多少種不同的方法?
這個問題的解法有很多,不過比較常見的就是遞歸算法和回溯算法。
什麼是回溯算法呢?
回溯算法其實也叫做試探法,它是一種搜索問題的解的方法。
它的的基本思想是在一個包含所有解的解空間樹中,按照深度優先的策略,從根結點出發搜索解空間樹。算法搜索至解空間樹的任意結點時,總是先判斷該結點是否肯定不包含問題的解。如果肯定不包含,則跳過對以該結點爲根的子樹的系統搜索,逐層向其祖先結點回溯。否則,進入該子樹,繼續按深度優先的策略進行搜索。
而回溯算法在用來求問題的所有解時,要回溯到根,且根結點的所有子樹都已被搜索遍才結束。
那什麼又是遞歸算法呢?
遞歸算法說白了就是一個過程或函數在其定義或說明中有直接或間接調用自身的一種方法。
而遞歸算法的本質及時遞歸函數,遞歸函數就是直接或間接調用自身的函數,也就是自身調用自己;是不是有點亂套啊,可能對於剛接觸遞歸的同學,可能難以理解遞歸,難以理解的點可能很多。我們以後慢慢來學,不着急。
介紹完這兩種算法之後,我們再來具體看下如何用這兩種算法來處理八皇后問題。
我們先來看回溯算法,也就是非遞歸算法的示例代碼:
#include <iostream>
using std::cout;
using std::endl;
#include <iomanip>
using std::setw;
#include <cmath>
//非遞歸算法解決八皇后問題。求出可能的92種。
// using std::abs;
int main()
{
static int queen[9];
static int count=1;
for (int A=1;A<=8;A++)
{
for (int B=1;B<=8;B++)
{
if (B==A)
{
continue;
}
queen[2]=B;
if ((abs(B-A))==1)
{
continue;
}
queen[1]=A;
for (int C=1;C<=8;C++)
{
if ((C==B) || (C==A))
{
continue;
}
if ((abs(C-B)==1)||(abs(C-A)==2))
{
continue;
}
queen[3]=C;
for (int D=1;D<=8;D++)
{
if ((D==C)||(D==B)||(D==A))
{
continue;
}
if ((abs(D-C)==1)||(abs(D-B)==2)||(abs(D-A)==3))
{
continue;
}
queen[4]=D;
for (int E=1;E<=8;E++)
{
if ((E==D)||(E==C)||(E==B)||(E==A))
{
continue;
}
if ((abs(E-D)==1)||(abs(E-C)==2)||(abs(E-B)==3)||(abs(E-A)==4))
{
continue;
}
queen[5]=E;
for (int F=1;F<=8;F++)
{
if ((F==E)||(F==D)||(F==C)||(F==B)||(F==A))
{
continue;
}
if ((abs(F-E)==1)||(abs(F-D)==2)||(abs(F-C)==3)||(abs(F-B)==4)||(abs(F-A)==5))
{
continue;
}
queen[6]=F;
for (int G=1;G<=8;G++)
{
if ((G==F)||(G==E)||(G==D)||(G==C)||(G==B)||(G==A))
{
continue;
}
if ((abs(G-F)==1)||(abs(G-E)==2)||(abs(G-D)==3)||(abs(G-C)==4)||(abs(G-B)==5)||(abs(G-A)==6))
{
continue;
}
queen[7]=G;
for (int I=1;I<=8;I++)
{
if ((I==G)||(I==F)||(I==E)||(I==D)||(I==C)||(I==B)||(I==A))
{
continue;
}
if ((abs(I-G)==1)||(abs(I-F)==2)||(abs(I-E)==3)||(abs(I-D)==4)||(abs(I-C)==5)
||(abs(I-B)==6)||(abs(I-A)==7))
{
continue;
}
queen[8]=I;
cout<<" NO."<<setw(2)<<count<<": ";
for (int i=1;i<=8;i++)
{
cout<<setw(3)<<queen[i];
}
count++;
cout<<endl;
}
}
}
}
}
}
}
}
return 0;
上面就是具體的示例代碼,大家可以自己在自己的電腦上調試下,我們再來看下用遞歸算法怎麼處理這個問題:
#include <iostream>
using namespace std;
//遞歸算法解決八皇后問題。總共有92種解法。
int c[20], n=8, cnt=0;
void print(){
for(int i=0; i<n; ++i){
for(int j=0; j<n; ++j){
if(j == c[i]) cout<<"1 ";
else cout<<"0 ";
}
cout<<endl;
}
cout<<endl;
}
void search(int r){
if(r == n){
print();
++cnt;
return;
}
for(int i=0; i<n; ++i){
c[r] = i;
int ok = 1;
for(int j=0; j<r; ++j)
if(c[r]==c[j] || r-j==c[r]-c[j] || r-j==c[j]-c[r]){
ok = 0;
break;
}
if(ok) search(r+1);
}
}
int main(){
search(0);
cout<<cnt<<endl;
return 0;
}
上面這部分這是遞歸算法的代碼,看着是不是比回溯算法的代碼少很多,具體可以在自己的電腦上試試。
好了,這個著名的問題我們就先聊到這裏,希望大家能夠支持。