n皇后问题:在一个n*n的国际象棋棋盘上放置n个皇后,使得这n个皇后两两均不在同一行、同一列、同一条对角线上,求合法的方案数。
解法:将其看成全排列问题,生成n的全排列,可确保其均不在同一行、同一列,接下来就是判断每两个皇后是否在同一条对角线上,利用count计数,合法的排列则使count加1,最后输出count。
朴素法代码如下:
1 #include<stdio.h> 2 #include<stdlib.h> 3 const int maxn = 11; 4 int n, P[maxn], hashTable[maxn] = {false}; 5 int count = 0; 6 void generateP(int index) 7 { 8 if(index == n+1) 9 { 10 bool flag = true; 11 for(int i = 1; i <= n; i++) 12 { 13 for(int j = i+1; j <= n; j++) 14 { 15 if(abs(i - j) == abs(P[i] - P[j])) 16 { 17 flag = false; 18 } 19 } 20 } 21 if(flag) 22 { 23 count ++; 24 } 25 return; 26 } 27 for(int x = 1; x <= n; x++) 28 { 29 if(hashTable[x] == false) 30 { 31 P[index] = x; 32 hashTable[x] = true; 33 generateP(index+1); 34 hashTable[x] = false; 35 } 36 } 37 } 38 int main() 39 { 40 n = 8; 41 generateP(1); 42 printf("%d", count); 43 return 0; 44 }
枚举所有情况计算量较大,事实上,可以发现,当已经放置了一部分皇后时(对应于已经生成排列的一部分时),可能剩余的皇后无论怎样放置都不可能合法,因此在排列的过程中进行检验,若有在同一对角线的元素,则停止递归,减少计算量。
采用回溯法的代码如下:
1 #include<stdio.h> 2 #include<stdlib.h> 3 const int maxn = 11; 4 int n, P[maxn], hashTable[maxn] = {false}; 5 int count = 0; 6 void generateP(int index) 7 { 8 if(index == n+1) 9 { 10 count++; 11 return; 12 } 13 for(int x = 1; x <= n; x++) 14 { 15 if(hashTable[x] == false) 16 { 17 bool flag = true; 18 for(int pre = 1; pre < index; pre++) //遍历之前的皇后 19 { 20 //第index列皇后的行号为x,第pre列皇后的行号为P[pre] 21 if(abs(index - pre) == abs(x - P[pre])) 22 { 23 flag = false; 24 break; 25 } 26 } 27 if(flag) 28 { 29 P[index] = x; 30 hashTable[x] = true; 31 generateP(index + 1); 32 hashTable[x] = false; 33 } 34 } 35 } 36 } 37 int main() 38 { 39 n = 8; 40 generateP(1); 41 printf("%d", count); 42 return 0; 43 }