問題描述:
在n×n格的棋盤上放置彼此不受攻擊的n個皇后。按照國際象棋的規則,皇后可以攻擊與之處在同一行或同一列或同一斜線上的棋子。
N後問題等價於再n×n的棋盤上放置n個皇后,任何2個皇后不可以在同一行或同一列或同一斜線上。
輸入:
給定棋盤的大小n (n ≤ 13)
輸出:
輸出有多少种放置方法。
解題思路:
要解決N皇后問題,其實就是要解決好怎麼放置這n個皇后,每一個皇后與前面的所有皇后不能在同一行、同一列、同一對角線,在這裏我們可以以行優先,就是說皇后的行號按順序遞增,只考慮第i個皇后放置在第i行的哪一列,所以在放置第i個皇后的時候,可以從第1列判斷起,如果可以放置在第1個位置,則跳到下一行放置下一個皇后。如果不能,則跳到下一列…直到最後一列,如果最後一列也不能放置,則說明此時放置方法出錯,則回到上一個皇后向之前放置的下一列重新放置。此即是回溯法的精髓所在。當第n個皇后放置成功後,即得到一個可行解,此時再回到上一個皇后重新放置尋找下一個可行解…如此後,即可找出一個n皇后問題的所有可行解。
//n皇后 回溯法 這裏是將數組x模擬爲二維數組,這裏的列不會重複,只需要判定行和對角線是否會重複
class Queen
{
friend int Nqueen(int n);//該類的友元函數
private:
//x[m]=n表示從第m列的從上往下數第n個元素,這個很重要,將一維的變爲二維
bool Place(int k)//該函數用來判斷該皇后是否處於合適位置
{
for (int i = 0; i < k; ++i)
{
if ( (x[i] == x[k]) || (abs(x[i] - x[k]) == abs(i - k)))//如果插入的元素和之前已插入元素在同一行或者同一列,則不能插入,返回false
{
return false;
}
}
return true;
}
void Backtrack(int i)
{
if (i == n)
{
for (int r = 0; r < n;++r)
{
for (int c = 0; c < n;++c)//按行打印
{
if (x[c] == r)
{
cout << "Q" << " ";
}
else
{
cout << "#"<<" ";
}
}
cout << endl;
}
cout << endl;
sum += 1;
}
else
{
//j=0 x[0],x[1],x[2],x[3]=0;每一列的第一行
for (int j = 0; j < n; ++j)
{
x[i] = j;//按列放入
if (Place(i))
{
Backtrack(i+1);
}
}
}
}
int n;//n後問題
int *x;//數組名
int sum;//皇后最多幾種擺放
};
int Nqueen(int n)
{
Queen Q;
Q.n = n;
Q.sum = 0;
Q.x = new int[n];
for (int i = 0; i < n; ++i) Q.x[i] = 0;//數組全置爲0
Q.Backtrack(0);//從第0列開始
delete[]Q.x;
return Q.sum;
}
void main()
{
int sum;
int n;
cin >> n;
sum = Nqueen(n);
cout <<"皇后最多種擺放個數" <<" "<<sum<< endl;
}