回溯——n皇后问题

思想:

用回溯方法求解,首先要分析问题的求解空间。可用一棵n叉树表示这个问题的求解空间,在回溯遍历这个课二叉树的过程中形成合理的解。

对于这棵n叉树,列序号i(0~n-1)是它的孩子,而每个孩子都有深度为n的子树(包括自身),这些子树的层次是n个皇后(也代表每个皇后的行序号,因为不同的皇后肯定不在同一行)。于是,遍历这个n叉树的每个孩子结点到叶子节点便得到一个合理解。遍历时,先从第一个孩子(第一行)开始遍历,深度遍历这个孩子子树,直到找到(1)一个合理解或者(2)剪去不存在合理解的分枝。对于(1)表明已经遍历到了叶子节点,亦即所有的皇后都找到了一个合理的位置,对于(2)表明在某个层次的皇后节点不能找到一个合理位置,于是停止深度遍历,将此分枝剪去。不管对于哪种情况,此时要向上层回溯,继续探索合理的解。直到整个n叉树都遍历完。

比如对于4个皇后的情况,首先让第一个皇后占据x[0][0](第一行第一列),然后让第二个皇后在第二行寻找合适的位置x[1][2](第二行,第3列),第三个皇后在第三行寻找合适的位置,此时第三个皇后已经不能找到合适位置,于是将此分枝剪去。回溯到第二个皇后(第二行),探索新的位置,此时对于第二个皇后已经不能找到合理位置。回溯到第一个皇后(第一行),探索新的位置。此时,让第一个皇后占据第一行第二列x[0][1],依次回溯,直到第一个皇后的所有列都试探完毕,也就遍历完了n叉树。

下面给出递归和非递归的实现:

递归实现: 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <math.h> 4 #define N 8 5 6 int x[N];//x[i]代表第i个皇后的列序号,行序号是下标i 7 int sum; 8 bool place(int i) 9 { 10 int j=0; 11 for(j =0;j<i;j++) 12 if(abs(x[i]-x[j]) == abs(i-j)|| x[j] == x[i]) 13 return false; 14 return true; 15 } 16 void back_queen(int t) 17 { 18 int i =0; 19 if(t>N-1) 20 sum++; 21 else 22 { 23 for(i=0;i<N;i++)//探索第t层(第t个皇后)的所有列号 24 { 25 x[t]=i; 26 if(place(t)) 27 back_queen(t+1); 28 x[t]=0; 29 } 30 } 31 } 32 int main() 33 { 34 back_queen(0); 35 printf("sum = %d/n",sum); 36 } ~ 迭代实现: 1 #include <stdio.h> 2 #include <stdlib.h> 3 #define N 8 4 5 int x[N]; 6 int sum; 7 bool place(int i) 8 { 9 int j=0; 10 for(j =0;j<i;j++) 11 if(abs(x[i]-x[j]) == abs(i-j)|| x[j] == x[i]) 12 return false; 13 return true; 14 } 15 void queen() 16 { 17 x[0]=-1;//初始化第一个皇后的坐标,在第一行第一列 18 int k = 0;//表示列号 19 while(k>=0) 20 { 21 x[k]+=1;//此时对于第k个皇后,列号向右移动,表示,当回溯到这一层时0~x[k]-1已经探索过了,接着往后探索 22 while(x[k]<N && !place(k)) x[k]++;//对于第k个皇后,找到一个合适的位置 23 if(x[k]<N) 24 { 25 if(k==N-1) 26 sum ++;//如果k已经是最后一个皇后,则找到了一个方案 27 else// 否则,继续探索下一个皇后 28 { 29 k++; 30 x[k] = -1; 31 } 32 } 33 else//对于第k个皇后,没有找到一个合适的位置,这相对于搜索树的第k层,于是对于这个节点的子树不再搜索,回溯到上一层 34 k--; 35 } 36 } 37 int main() 38 { 39 queen(); 40 printf("sum = %d/n",sum); 41 }

你可能感兴趣的:(ini,math.h)