八皇后问题的两种解法

八皇后问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果

八皇后问题往往还需要使用递归。

Lz查找到几种不同的解决方案,现列出其中两种并做了必要注释,仅供参考。

第一种:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #define N 8
 4 
 5 int column[N+1]; // 同栏是否有queen,1表示有
 6 int rup[2*N+1]; // 右上至左下是否有queen,1表示有
 7 int lup[2*N+1]; // 左上至右下是否有queen,1表示有
 8 int queen[N+1] = {0};    
 9 int num; //不同解的编号
10 
11 void showAnswer() {
12     int x, y;
13     printf("\n解答 %d\n", ++num);
14    
15     for(y = 1; y <= N; y++) 
16     {
17         for(x = 1; x <= N; x++) 
18         {
19             if(queen[y] == x)   //queen[y]表示第y行第x个位置有queen
20             {
21                 printf(" Q");
22             }
23             else 
24             {
25                 printf(" *");
26             }
27         }
28         printf("\n");
29     }
30 }
31 
32 void backTrack(int i)   //递归求解
33 {
34     int j;
35 
36     if(i > N)
37     {
38         showAnswer();   //每求出一个解便输出一个
39     }
40     else 
41     {
42         for(j = 1; j <= N; j++)
43         {
44             if(column[j] == 1 && rup[i+j] == 1 && lup[i-j+N] == 1)   //如果符合条件
45             {
46                 queen[i] = j;// 设定[i,j]为占用,第i行第j列为queen
47 
48                 column[j] = rup[i+j] = lup[i-j+N] = 0;    
49                 //第i行第j列为queen,所以把第j列设为0;rup[i+j]为0表示经过[i,j]从右上到左下的斜线设为0;lup表示经过[i,j]左上到右下的斜线设为0
50                
51                 backTrack(i+1);  // 到下一行
52                 column[j] = rup[i+j] = lup[i-j+N] = 1;  //递归操作用到栈,这句会被压倒栈里,最后执行这句,将之前设置成0的位置再设置为1
53             }
54         }
55     }
56 }
57 
58 int main(void) {
59     int i;
60     num = 0;
61 
62     for(i = 1; i <= N; i++)
63         column[i] = 1;
64 
65     for(i = 1; i <= 2*N; i++)   //rup和lup下标从 0 到 2*N
66         rup[i] = lup[i] = 1;
67 
68     backTrack(1);
69 
70     return 0;
71 }

 

第二种:

 1 #include <stdio.h>
 2 #include <math.h>
 3 
 4 #define QUEENS 8
 5 
 6 int iCount = 0;        //记录解的序号
 7 int Site[QUEENS];   //queen在各行上的位置
 8 void Queen(int n);  //递归求解
 9 void Output();        //输出一个解
10 int IsValid(int n); //判断第n个queen放上去之后是否有冲突
11 
12 void main() 
13 { 
14     Queen(0);  //从第0行开始递归试探   
15 }
16 
17 void Queen(int n) 
18 {    
19     int i;    
20     if(n == QUEENS)  //参数n从0开始,等于8时便试出了一个解,将它输出并回溯 
21     {      
22         Output();       
23         return;    
24     }   
25     
26     for(i = 1 ; i <= QUEENS ; i++)  //n还没到8,在第n行的各个行上依次试探   
27     {      
28         Site[n] = i;     //在该行的第i行上放置皇后      
29         
30         if(IsValid(n))   //如果放置没有冲突,就开始下一行的试探     
31             Queen(n + 1);  
32           }
33 }
34 
35 int IsValid(int n)    //判断函数
36 {   
37     int i;   
38     for(i = 0 ; i < n ; i++)  //将第n个queen的位置依次于前面n-1个queen的位置比较  
39     {       
40         if(Site[i] == Site[n])  //判断两个queen是否在同一列  
41             return 0;         
42         
43         if(abs(Site[i] - Site[n]) == (n - i))  //判断两个queen是否在对角线上
44             return 0;   
45     }   
46     return 1; //没有冲突则返回1
47 }
48 
49 void Output()
50 {    
51     int i;   
52     printf("No.%-5d" , ++iCount);    //输出序号,控制格式
53                 
54     for(i = 0 ; i < QUEENS ; i++)    //依次输出各个行上的queen的位置,即所在的列数      
55     printf("%d " , Site[i]);   
56                 
57     printf("\n");
58 }  

 

posted @ 2014-04-13 17:12  Cay Chan  阅读(796)  评论(0编辑  收藏  举报