八皇后問題不同思路解答:
算法提出:
在國際象棋棋盤上(8*8)放置八個皇后,使得任意兩個皇后之間不能在同一行,同一列,也不能位於同於對角線上。問共有多少種不同的方法,並且指出各種不同的放法。
思路一:回溯法
/*
算法提出:
在國際象棋棋盤上(8*8)放置八個皇后,使得任意兩個皇后之間不能在同一行,同一列,也不能位於同於對角線上。問共有多少種不同的方法,並且指出各種不同的放法。
算法思路:
首先我們分析一下問題的解,我們每取出一個皇后,放入一行,共有八種不同的放法,然後再放第二個皇后,同樣如果不考慮規則,還是有八种放法。於是我們可以用一個八叉樹來描述這個過程。從根節點開始,樹每增加一層,便是多放一個皇后,直到第8層(根節點爲0層),最後得到一個完全八叉樹。
緊接着我們開始用深度優先遍歷這個八叉樹,在遍歷的過程中,進行相應的條件的判斷。以便去掉不合規則的子樹。
那麼具體用什麼條件來進行子樹的裁剪呢?
我們先對問題解的結構做一個約定。
用X[i]來表示,在第i行,皇后放在了X[i]這個位置。
於是我們考慮第一個條件,不能再同一行,同一列於是我們得到x[i]不能相同。剩下一個條件是不能位於對角線上,這個條件不是很明顯,我們經過分析得到,設兩個不同的皇后分別在j,k行上,x[j],x[k]分別表示在j,k行的那一列上。那麼不在同一對角線的條件可以寫爲abs((j-k))!=abs(x[j]-x[k]),其中abs爲求絕對值的函數。
於是下面我們便可以利用一個遞歸的調用來遍歷八叉樹。
*/
#include <iostream>
#include <cmath>
using namespace std;
static int num; //皇后數目
static int *x; //存放皇后位置的數組
static int sum; //方案數目
//判斷位置是否符合條件
bool place(int k)
{
for(int j = 1;j<k;j++)
if(abs(x[k] - x[j]) == abs(k-j) || x[j] == x[k])
return false;
return true;
}
//訪問某節點所有子節點
void backtrack(int t)
{
if(t>num) //num爲皇后的數目
{
sum++;//sum爲所有的可行的解
for(int m = 1;m<num;m++)
{
cout<<x[m]<<" ";//這一行用輸出當遞歸到葉節點的時候,一個可行解
}
cout<<endl;
}
else
for(int i = 1;i<=num;i++)
{
x[t] = i;
if(place(t)) backtrack(t+1);//此處的place函數用來進行我們上面所說的條件的判斷,如果成立,進入下一級遞歸
}
}
int main()
{
num = 8;
sum = 0;
x = new int[num+1];
for(int i= 0;i<=num;i++)
x[i] = 0;
backtrack(1);
cout<<"方案共有"<<sum<<endl;
return 0;
}