思想:
用回溯方法求解,首先要分析问题的求解空间。可用一棵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叉树。
下面给出递归和非递归的实现:
view plaincopy to clipboardprint?
递归实现:
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 #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 }
~ view plaincopy to clipboardprint?
迭代实现:
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 }
本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/clearriver/archive/2009/06/21/4287283.aspx
711

被折叠的 条评论
为什么被折叠?



