算法学习->递归典例N皇后问题

 

00 问题

在N✖N(这个N==N皇后的N)的方格棋盘上放置n个皇后,要求:1.每个皇后在不同行不同列;2.每个皇后在不同左右对角线

输出要求:输出符合条件的所有解,解以皇后的坐标的形式。

01 思路

拿到这个问题如果用蛮力,那么OK,把皇后序号与行的序号关联在一起,去探查列,每多放一个皇后,就是一遍遍地回头遍历检查二维数组的事情;

但是如果想一下,用归纳法,我们考虑一下每一次放皇后的过程,我们需要考虑哪些因素,以及执行哪些步骤?

如果是放第一个皇后,那么ok,无条件返回true,因为没有限制条件,第一行任何一列都符合条件。

else 如果是中间的皇后,比如第i个皇后,那么从第i行头考虑,逐列探查,每一列得考虑前i-1的皇后,每一个都得拎出来检查一下条件,来确保第i个皇后所放的列是对的

这样就会发现,每一次放皇后取决于前面的皇后,而第一个随便放,皇后个数不超过n,这样就可以设计递归出口和递归主体了。出口是到n,主体就是前面的if-else。

主体的if-else可以再分几步:

  • 逐列,是一次循环

  • 探查,可以写一个函数

  • 探查函数中,探查需从第0个皇后查起,是一个循环

  • 探查函数返回许可,主控函数queen递归下一个皇后

  • 递归终点即n行走完,所有皇后落位。

02 代码


 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #define N 20
 4  5 int q[N];//存皇后的列数(从0开始
 6 int count = 0;
 7 void dispasolution(int n){
 8     printf("The %dth个解:", ++count);
 9     for(int i=0;i<=n;i++){
10         printf("(%d,%d)", i,q[i]);
11     }
12     printf("\n");
13 }
14 bool place(int i, int j){
15     if(i==1)return true;//第一个必定正确
16     int k=1;
17     while(k<i){
18         if(q[k]==j||abs(q[k]-j)==abs(i-k)){
19             return false;
20         }
21         k++;
22     }
23     return true;
24 }
25 void queen(int i, int n){
26     if(i>n)dispasolution(n);//递归出口,输出
27     else{
28         for(int j=1;j<=n;j++){
29             if(place(i,j)){//如果符合条件就把第i个皇后放下去,进一步递归
30                 q[i]=j;
31                 queen(i+1,n);
32             }
33         }
34     }
35 }
36 37 int main(){
38     int n;
39     printf("皇后问题(n<20)n=");
40     scanf("%d",&n);
41     if(n>20){
42         printf("n is too big!\n");
43     }
44     else{
45         printf("%d皇后问题的求解如下:\n",n);
46         queen(1,n);//调用递归主控函数
47     }
48     return 0;
49 }

 

03 测试

示例 n=6

1 皇后问题(n<20)n=6
2 6皇后问题的求解如下:
3 The 1th个解:(0,0)(1,2)(2,4)(3,6)(4,1)(5,3)(6,5)
4 The 2th个解:(0,0)(1,3)(2,6)(3,2)(4,5)(5,1)(6,4)
5 The 3th个解:(0,0)(1,4)(2,1)(3,5)(4,2)(5,6)(6,3)
6 The 4th个解:(0,0)(1,5)(2,3)(3,1)(4,6)(5,4)(6,2)

 

 

 

 

posted @ 2021-10-14 22:49  climerecho  阅读(196)  评论(0编辑  收藏  举报