回溯算法与八皇后问题N皇后问题_第1页
回溯算法与八皇后问题N皇后问题_第2页
回溯算法与八皇后问题N皇后问题_第3页
回溯算法与八皇后问题N皇后问题_第4页
回溯算法与八皇后问题N皇后问题_第5页
已阅读5页,还剩6页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、回溯算法与八皇后问题(N皇后问题)1 问题描述八皇后问题是数据结构与算法这一门课中经典的一个问题。下面再来看一下这个问题的描述。八皇后问题说的是在8*8国际象棋棋盘上,要求在每一行放置一个皇后,且能做到在竖方向,斜方向都没有冲突。更通用的描述就是有没有可能在一张N*N的棋盘上安全地放N个皇后?2 回溯算法              回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。在现

2、实中,有很多问题往往需要我们把其所有可能穷举出来,然后从中找出满足某种要求的可能或最优的情况,从而得到整个问题的解。回溯算法就是解决这种问题的“通用算法”,有“万能算法”之称。N皇后问题在N增大时就是这样一个解空间很大的问题,所以比较适合用这种方法求解。这也是N皇后问题的传统解法,很经典。下面是算法的高级伪码描述,这里用一个N*N的矩阵来存储棋盘:1) 算法开始, 清空棋盘,当前行设为第一行,当前列设为第一列2) 在当前行,当前列的位置上判断是否满足条件(即保证经过这一点的行,列与斜线上都没有两个皇后),若不满足,跳到第4步3) 在当前位置上满足条件的情形:在当前位置放一个皇后,若当前行是最后

3、一行,记录一个解;若当前行不是最后一行,当前行设为下一行, 当前列设为当前行的第一个待测位置;若当前行是最后一行,当前列不是最后一列,当前列设为下一列;若当前行是最后一行,当前列是最后一列,回溯,即清空当前行及以下各行的棋盘,然后,当前行设为上一行,当前列设为当前行的下一个待测位置;以上返回到第2步4) 在当前位置上不满足条件的情形:若当前列不是最后一列,当前列设为下一列,返回到第2步;若当前列是最后一列了,回溯,即,若当前行已经是第一行了,算法退出,否则,清空当前行及以下各行的棋盘,然后,当前行设为上一行,当前列设为当前行的下一个待测位置,返回到第2步;  算法的基本原理

4、是上面这个样子,但不同的是用的数据结构不同,检查某个位置是否满足条件的方法也不同。为了提高效率,有各种优化策略,如多线程,多分配内存表示棋盘等。为了便于将上述算法编程实现,将它用另一种形式重写:Queen()Loop:      if check_pos(curr_row, curr_col) = 1 then             put_a_queen(curr_row, curr_col);

5、0;            if curr_row = N then                    record_a_solution();           

6、  end if;                   if curr_row != N then                    curr_row = curr_row + 1;&#

7、160;                   curr_col = 1;             else              

8、60;     if curr_col != N then                           curr_col = curr_col + 1;          

9、          else                           backtrack();          &#

10、160;         end if;             end if;            else            &#

11、160;if curr_col != N then                    curr_col = curr_col +1;             else        &#

12、160;           backtrack();             end if;           end if;end Queen;3 实现3.1 数据结构这里,用一个N个元素的一维数组来表示。数组的下标表示棋盘的行,数组的元素表示

13、该行皇后所在的列。这个结构自然就消除了列冲突,因为每一行只有一个皇后。还有利用它解决行冲突,也很简单,只要比较各个元素就行了,看有没有相等的元素。斜线冲突也简单,因为同一斜线上的在一直线上,该直线的斜率为+1(左下至右上)或-1(左上至右下),所以,左下至右上的冲突检测方法为看式子是否成立(row curr_row)/(col curr_col) = 1,也就是(row - col) = (curr_row curr_col),相同,则有冲突。同理,左上至右下看式子(row + col) = (curr_row +curr_col)。这里,也是看下标与其对应元素的和与差是不是与要检测位置的相应

14、结果相同,如果有一个相同,就有冲突。数据结构一确定,冲突检测方法就有了,关键的部分的算法就完成了。3.2 代码/*     File: NQueen.c     Descripton: N皇后问题求解之回溯版     Author: liuqh, Hunan University     Date: 2007.5.22, Tues.     Version: 1.0*/#include <s

15、tdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <math.h>#define SOLS(n)     (int)(pow(2.0, (double)(n)#define DEBUG/*全局变量定义*/int N = -1;               

16、0;        /*棋盘的大小*/char *p_board = NULL;        /*指向棋盘,这里是用一个长度为N的一维数组表示的*/char *buf = NULL;     /* 输出缓冲 */int buf_index = -1;/*     本编译单元的函数声明*/static int queen(FILE *fp);static int clear_b

17、oard(int i);static int check_pos(int curr_row);static int record_a_solution(FILE *fp, int solutions);static int backtrack(int *p_curr_row);static void flush_buf(FILE *fp, int solutions);/* 函数:main()* 功能:程序入口* 入口: 参数个数(整型);程序名与N的大小* 出口:* 返回:成功返回0,否则返回-1* 备注:*/int main(int argc, char *argv)clock_t sta

18、rt, finish;double       duration;int solutions;FILE *fp;/* 命令行参数检查*/            if (argc != 2)                 fprintf(stderr, "用法:

19、0;    queen Nn") ;                   return -1;            N = atoi(argv1);          

20、  if (N <= 0)                 fprintf(stderr, "用法:     queen N n N必须大于0n") ;                   re

21、turn -1;                          /*开始计时*/            start = clock();        &#

22、160;           p_board = (char*)calloc(N, sizeof(char);            if (NULL = p_board)                   

23、      fprintf(stderr, "为棋盘分配内存失败n") ;                    return -1;                 &

24、#160;                 fp = NULL;if (fp = fopen("solutions.txt", "w") = NULL)      free(p_board);             fprintf(std

25、err, "创建文件solutions.txt失败!n") ;             return -1;         solutions = queen(fp);if (-1 = solutions)     free(p_board);     if (fclose(fp) =

26、EOF)                  fprintf(stderr, "关闭文件solutions.txt失败!n") ;             return -1;           &#

27、160;        fprintf(stderr, "调用queen()失败n") ;                   return -1;               printf

28、("共有%d种解决方案,具体结果请查看文件solutions.txtn", solutions) ;           fprintf(fp, "solutions = %dn", solutions);free(p_board);/*操作完成,计时结束*/finish = clock();/*计算时间间隔,以秒为单位*/duration = (double)(finish - start) / CLOCKS_PER_SEC;printf("计

29、算完毕,共耗时%f秒!n", duration);fprintf(fp, "time = %fn", duration);if (fclose(fp) = EOF)            fprintf(stderr, "关闭文件solutions.txt失败!n") ;            return -1; &

30、#160; return 0;/* 函数:queen()* 功能:计算N皇后问题的解* 入口: 记录结果的文件指针* 出口:* 返回:成功返回解的个数,出错返回-1* 备注:*/int queen(FILE *fp)int curr_row;int result;    result = 0;if (clear_board(0) = -1)     fprintf(stderr, "清空棋盘失败!n") ;      

31、0;     return -1; curr_row = 0;p_boardcurr_row = (char)0;            buf = (char*)calloc(SOLS(N)*N, sizeof(char);            if (NULL = buf)     

32、                    fprintf(stderr, "为解分配内存失败n") ;                    return -1;    &

33、#160;                          while (1)      if (check_pos(curr_row)= 1)           if (N-1 = curr_row) &

34、#160;           result+;       record_a_solution(fp, result);                   if (curr_row != N-1)       

35、60;     curr_row+;       p_boardcurr_row     = (char)0;       continue;                    if (p_boardcurr_row 

36、;    != (char)(N-1)           p_boardcurr_row +;          else           if (backtrack(&curr_row) = 1)         

37、    break;           /* end while */flush_buf(fp, result);free(buf);return result;/* 函数:clear_board()* 功能:初始化棋盘* 入口: 初始化开始的行(整型), 全局变量p_board, N* 出口:初始化后的棋盘,这里指指针p_board指向的数组* 返回:成功返回0,出错返回-1* 备注:*/int clear_board(int i)if (memset(&p_bo

38、ardi, -1, N-i) = NULL)     return -1;return 0;/* 函数:check_pos()* 功能:检查某个位置是否能放一个皇后* 入口: 位置所在的行(整型), 全局变量p_board, N* 出口:* 返回:可以放置的话返回1,否则返回0* 备注:*/int check_pos(int curr_row)int i;int sum, sub;/*检查是否有行冲突*/for (i = 0; i < curr_row; i+)     if (p_boardi = p_bo

39、ardcurr_row)           return 0;     /*检查斜线方向的冲突*/sum = curr_row + p_boardcurr_row;sub = curr_row - p_boardcurr_row;for (i = 0; i < curr_row; i+)     if (i+p_boardi = sum | i - p_boardi = sub)   &#

40、160;       return 0;     return 1;/* 函数:record_a_solution()* 功能:记录一个合法的解* 入口:记录结果的文件指针;解的个数(整型) 全局变量p_board, N* 出口:存储解的缓存buf(字符串)* 返回:成功,返回0,否则返回-1* 备注:解先缓存在内存中,这样快一点,要提高速度,修改SOLS宏以获得更大的缓冲区*/int record_a_solution(FILE *fp, int solutions) if (+buf_index

41、60;    != SOLS(N)     if (memcpy(&bufbuf_index*N, p_board, N) = NULL)           fprintf(stderr, "拷贝解到缓冲时出错!n") ;      buf_index-;      return -1;  

42、;   else     flush_buf(fp, solutions); return 0;/* 函数:backtrack()* 功能:回溯到上一行* 入口:     全局变量p_board, N* 出口:当前行(整型指针)* 返回:可以回溯,返回0,否则返回1,表示算法可以退出了* 备注:可能递归调用自身*/int backtrack(int *p_curr_row)if (0 = *p_curr_row)     if (clear_board(p_board*p_curr_row) = -1)           fprintf

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论