Fork me on GitHub

n皇后问题(分析)

这道题需要用到回溯算法,现在在这里先简单的介绍一下这个算法:

回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。用回溯算法解决问题的一般步骤为:

1、定义一个解空间,它包含问题的解。

2、利用适于搜索的方法组织解空间。

3、利用深度优先法搜索解空间。

4、利用限界函数避免移动到不可能产生解的子空间。

问题的解空间通常是在搜索问题的解的过程中动态产生的,这是回溯算法的一个重要特性。

 

首先,看一个简单的程序;

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 void function(int a)
 5 {
 6     if (a > 0)
 7     {
 8         printf("%d\n", a);
 9         function(a - 1);
10     }
11 }
12 
13 int main(void)
14 {
15     int a = 3;
16     function(3);
17     system("PAUSE");
18     return 0;
19 }

输出:3 2 1

 

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 void function(int a)
 5 {
 6     if (a > 0)
 7     {
 8         function(a - 1);
 9                 printf("%d\n",a);
10     }
11 }
12 
13 int main(void)
14 {
15     int a = 3;
16     function(3);
17     system("PAUSE");
18     return 0;
19 }

输出:1 2 3

首先第一个不难理解,第二个,首先进行三次递归,分别是function(2),function(1),function(0)=>a=3,a=2,a=1;当到a=1递归执行结束,就会接着往下执行,执行printf,所以此时输出1,然后,返回到上一级递归,function(1),执行结束后,再次执行printf,输出1...

 

八皇后问题:

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

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 #define max 8//定义最大方格 
 5 
 6 int a[max],sum=0;//定义全局变量
 7 
 8 int check_function(int n) { //检查当定一个点时,以行为单位扫描(a[n]为横坐标)遍历其他列的位置是否能满足要求
 9     int i;
10     for(i=0; i<n; i++)/*i<n,而不是i<max,这里用法是:首先定的一个点为起始点,这个点肯定正确,然后对下列扫描,找到,和上一列定那个点一起满足条件的点,接着第三第四列一样,到第八列(max),又找到点时,这时候满足第30行代码的输出条件,输出,找到一组
11     ,接着第26~28行代码,相当于将定点纵坐标加一,进行移位操作,然后到check_function函数中进行与上面类似的操作*/
12     {
13         if(a[i]==a[n]||abs(a[i]-a[n])==abs(i-n)) { //a[i]==b[n]表示在同一排的情况,后者为在同一对角线上(记住abs求绝对值函数)
14             return 1;//不满足条件返回1
15         }
16     }
17     return 0;//满足条件返回0
18 
19 }
20 
21 int func(int n) { //定义一个进行对定点改变与输出结果的函数
22     int i,t;
23     for(i = 0; i < max; i++) {
24         a[n]=i;//假设的点,当每次满足条件返回1时,会再次进行上面的for循环,对i进行加一操作,相当于对纵坐标操作,下移一位
25         if(check_function(n)==0) { //结合上一个给a[n]赋值,通过判断是否符合条件,让a[n]的值为每一列满足条件的值(纵坐标),n为横坐标
26             if(n==max-1) { //max-1 说的是最后一列,当横坐标数等于最后一列,且满足了检验,就说明这是一组中的最后一个,于是输出满足条件的a[n]
27                 for(t=0; t<n; t++)
28                     printf("(%d,%d),",t,a[t]);//这样打印的原因:到这里,每个a[n]实际是满足条件的位置
29                 printf("\n");
30                 sum++;
31             } else {
32                 func(n+1);//若满足了检验,却不满足是最后一项,则说明这只是一组中的一个,且不是最后一个,因为推出结果是按列进行扫描,所以,横坐标向后移一位
33             }
34         }
35     }
36 }
37 
38 
39 int main(void) {
40     func(0);//定横坐标为零
41     printf("sum=%d\n",sum);//打印出摆放方式数
42     return 0;
43 }

 

posted @ 2018-03-04 21:09 Hk_Mayfly 阅读(...) 评论(...) 编辑 收藏