“發光並非太陽的專利,你也可以發光。”
你好,我是夢陽辰!期待與你相遇!
【問題描述】1.設計算法求解N皇后問題,要求給出測試用例,並給出你的程序運行該測試案例之後得到的結果。
N皇后問題研究的是如何將 N個皇后放置在 N×N 的棋盤上,並且使皇后彼此之間不能相互攻擊。
(1) 給定一個整數N,返回所有不同的N皇后問題的解決方案。
(2) 如果只讓求解N皇后問題不同解法的數目,又該如何設計算法。
(1)算法的描述:
1.定義解空間:
n皇后問題要求每一個皇后在不同行、不同列、不同斜線,因此我們可以使用不同行、不同列作爲顯約束,隱約束選擇不同斜線。這樣選擇可以將解空間大大縮小。從根到葉子的路徑就是一個解空間樹。
(2)搜索解空間
1.約束條件:在第i行第j列放置第i個皇后時不能 `前i-1個皇后在同一斜線。根據行列與斜線的映射關係可知,該位置所在斜線的標號,若標記數組中該位置爲false表示此斜線還可以放置皇后,否則該位置不能放。
2.限界條件:該問題不存在放置方案好壞的問題,所以不需要設置限界條件。
3.搜索過程:搜索過程從根開始,以深度優先方式進行搜索,根結點是活結點,並且是當前的擴展結點。在搜索過程中,當前的擴展結點沿縱深方向移向一個新結點, 判斷該新結點是否滿足隱約束。如果滿足,則新結點成爲活結點,繼續深一層的搜索;如果不滿足,則換到該新結點的兄弟結點繼續搜索;如果新結點沒有兄弟結點。或者其他兄弟結點已經全部搜索完畢,則擴展結點成爲死結點,搜索回溯到其父結點處繼續進行。搜索過程直到找到問題的根結點變爲死結點爲止。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<unsigned>nd;
int n, num;
bool p;//選擇是否輸出所有排列方式
vector<bool>l_r, r_l;//標記列,從左到右的斜線,和從右到左的斜線是否已經訪問過
//不能放置物品爲false 否則爲true
inline void init()
{
nd.resize(n);
l_r.assign(2 * n - 1, true);
r_l.assign(2 * n - 1, true);
for (int i = 0; i < n; i++)nd[i] = i;
num = 0;
}
inline void mapping(int cur, int& _l_r, int &_r_l)
{
_l_r = cur + nd[cur];
_r_l = (n - 1 - cur) + nd[cur];
}
inline bool judge(int cur)//判斷當前位置能否放置皇后
{
int lr, rl;
mapping(cur, lr, rl);
return l_r[lr] && r_l[rl];
}
void dfs(int cur,int k)//排列樹優化
{
int i, lr, rl;
if (cur == n)//找到一種放置方法
{
num++;
if (p) {
cout << "---------------------------------------------------" << endl;
cout << "第" << num << "個滿足要求的皇后位置:" << endl;
i = 0;
for (auto it : nd)//打印符合要求的位置
{
cout << "(" << i++ << "," << it << ") ";
}
cout << "\n--------------------------------------------------" << endl;
cout << "---------------------------------------------------" << endl;
cout << "第" << num+1 << "個滿足要求的皇后位置:" << endl;
i = 0;
for (auto it : nd)//打印符合要求的位置
{
cout << "(" << i++ << "," << n-1-it << ") ";
}
cout << "\n--------------------------------------------------" << endl;
}
num++;
}
else
{
for (i = cur; i <k; i++)
{
swap(nd[cur], nd[i]);//依次和後面的第cur-k個元素交換位置
if (judge(cur))//判斷隱約束是否滿足要求
{
mapping(cur, lr, rl);//得到映射關係
//標記
l_r[lr] = false;
r_l[rl] = false;
if (cur == 0 && n % 2 != 0 && nd[cur] == n / 2)
{
dfs(cur + 1, (n + 1) / 2);
}
else
dfs(cur + 1, n);
//回退
l_r[lr] = true;
r_l[rl] = true;
}
swap(nd[cur], nd[i]);
}
}
}
int main()
{
//freopen("debug.txt", "r", stdin);
int N;
cout << "請輸入測試數據個數:";
cin >> N;
while (N--)
{
cout << "請輸入皇后的個數:";
cin >> n;
cout << "請選擇是否要輸出所有排列(’1‘ or ‘0’,‘1’表示輸出,‘0’表示不輸出):" << endl;
cin >> p;
init();
dfs(0,(n+1)/2);
cout << "共有" << num<< "種方案" << endl;
}
return 0;
}
測試用例及運行結果:
皇后的個數:2 5
方案個數 :0 10
“別人能做到的事,我一定也能做到”
關注公衆號【輕鬆玩編程】回覆關鍵字“電子書”,“計算機資源”,“Java從入門到進階”,”JavaScript教程“,“算法”,“Python學習資源”,“人工智能”等即可獲取學習資源