這是一道深搜題目!問題的關鍵是在剪枝。
下面我們對問題進行分析:
1.一行只能放一個皇后,所以我們一旦確定此處可以放皇后,那么該行就只能放一個皇后,下面的就不要再搜了。
2.每一列只能放一個皇后,所以我們下次搜索就不要再搜已經放過的皇后了。
3.斜的45°線也只能放一個。
綜上如何才能最快速的確定一列和45°是否用過這個是個關鍵步驟,一旦此步驟確定我們就可以很快的進行搜索了。
我們用三個數組來保存他的每一個狀態及(三個方向 ↖ ↑ ↗)
但是如果我們保存↑(每一列方向上的皇后)是非常容易保存的 但是保存( 這兩個方向上的狀態就不容易了↖ ↗)
再分析,在這個(↖)方向上的數據的行和列有什么特點
0 1 2 3 4
-1 0 1 2 3
-2 -1 0 1 2
-3 -2 -1 0 1
-4 -3 -2 -1 0
將此表列出我們就應該知道在(↖)方向上的數據的行和列的特點了,及 在 (↖)方向上 列 - 行 的差是相等的。
假如我們用數組保存負數肯定是不行的, 所以我們要加上 n,讓他變為非負.
再分析,在這個( ↗)方向上的數據的行和列有什么特點
0 1 2 3 4
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
將此表列出我們就應該知道在(↗)方向上的數據的行和列的特點了,及 在 (↗)方向上 列 + 行 的和是相等的。
知道數據怎么處理就可以解決問題了。
下面附上參考代碼:
1 #include<iostream> 2 #include<cstring> 3 #include<cmath> 4 using namespace std; 5 int vis[3][50], P[15];//三個方向 ↖↑↗在此三個方向都不能有皇后 6 int n, sum; 7 8 void DFS(int row); 9 10 int main() 11 { 12 for(n = 1; n <= 10; n++)//先打表不然會超時的 13 { 14 memset(vis,0,sizeof(vis)); 15 sum = 0; 16 DFS(1); 17 P[n] = sum; 18 } 19 while(scanf("%d",&n), n) 20 { 21 printf("%d\n",P[n]); 22 } 23 return 0; 24 } 25 26 void DFS(int row) 27 { 28 int i; 29 if(row == n + 1)//已經夠n行了 30 { 31 sum ++; 32 return ; 33 } 34 for(i = 1; i <= n; i++) 35 { 36 if(vis[0][row-i+n] == 0 && vis[1][i] == 0 && vis[2][row+i] == 0) 37 {//不會回溯的同學要好好看看學習學習 38 vis[0][row-i+n] = vis[1][i] = vis[2][row+i] = 1;//變值 39 DFS(row + 1);//深搜 40 vis[0][row-i+n] = vis[1][i] = vis[2][row+i] = 0;//回溯 41 } 42 } 43 }