N皇后問題解法及解的個數
一、什麼是N皇后問題?
在n×n格的棋盤上放置彼此不受攻擊的n個皇后。按照國際象棋的規則,皇后可以攻擊與之處在同一行或同一列或同一斜線上的棋子。n後問題等價於再n×n的棋盤上放置n個皇后,任何2個皇后不妨在同一行或同一列或同一斜線上。
二、演算法
1、將第一個皇后放置在第一行的第一個空格里
2、對於第二行,從第一個空格開始尋找不與第一行的皇后衝突的空格。找到的第一個不衝突的空格是第2個。
3、對於第三行,這時已經找不到與之前放置的兩個皇后不衝突的空格了。把當前行恢復初始狀態,返回到上一行。
4、在當前行皇后所佔的空格之後尋找一個不與之前皇后衝突的位置。有兩種情況,如果找打了則把當前行的皇后移動到該位置,然後處理下一行。如果直到最後當前行的最後一個空格也沒有找合適的位置,則把當前行恢復初始狀態,繼續回溯到上一行。
5、把最後一個皇后成功安置在最後一行,代表找到了一種可行解。返回步驟4。
6、當需要回溯到第0行(表格之外)的時候代表已經找遍了所有可能的可行解。
三、4皇后解法圖解
第一步
Q |
第二步
Q |
Q |
第三步 發現第三行沒有合適的位置了,於是將第二行皇后的位置移到下一個不衝突的位置
Q |
Q |
第四步
Q |
Q |
Q |
第五步 發現第四行沒有合適的位置了,於是回溯到第二行,又發現第二行到頭了,於是繼續回溯到第一行。把第一行皇后的位置後移。
Q |
Q |
第六步
Q |
Q |
Q |
第七步
Q |
Q |
Q |
Q |
四、程式
#include "stdafx.h" #include <iostream> using namespace std; int n=0; int arr[100]; bool place(int i) //判斷能不能放置第N個皇后 { for(int j=0;j<i;j++) if(arr[j]==arr[i]||abs(arr[j]-arr[i])==abs(j-i)) return false; return true; } int queue(int n) { int solution=0; for(int i=0;i<n;i++) arr[i]=0; int k=1; while(k>=0) { while(!place(k)&&k<n) //放置第N個皇后 arr[k]=arr[k]+1; if(arr[k]<n&&k==n-1) //排列完成一次 { solution++; arr[k]=arr[k]+1; } else if(arr[k]<n&&k<n-1) //排列完一個皇后 { k=k+1; arr[k]=-1; } else //當前皇后沒有合適的位置 { arr[k]=0; k=k-1; arr[k]=arr[k]+1; } } return solution; } void main() { while(1) { cout<<"Please input the queue number:"<<endl; cin>>n; if(n==-1) break; int x=queue(n); cout<<x<<" solution(s)"<<endl; } system("pause"); }
五、N皇后問題解的個數
n solution(n)
1 1
2 0
3 0
4 2
5 10
6 4
7 40
8 92
9 352
10 724
11 2680
12 14200
13 73712
14 365596
15 2279184
16 14772512
17 95815104
18 666090624
19 4968057848
20 39029188884
21 314666222712
22 2691008701644
23 24233937684440
24 227514171973736
25 2207893435808352
以上結果可以作為測試案例驗證程式。