码迷,mamicode.com
首页 > 其他好文 > 详细

广度优先搜索(二)

时间:2016-02-06 22:14:58      阅读:240      评论:0      收藏:0      [点我收藏+]

标签:

【例5】 8数码难题

【问题描述】:

在 3 * 3 的棋盘上,摆有八个棋子,每个棋子上标有 1 至 8 的某一数字。棋盘中留有一个空格。空格周围的棋子可以移到空格中。要求解的 问题是,给出一种初始布局 [ 初始状态 ] 和目标布局 [ 目标状态 ] ,找到一种移动的方法,实现从初始布局到目标布局的转变。

【输入格式】

输入由两行组成,每行9个数,分别表示初始状态和目标状态:

【输出格式】

有若干行,第一行表示最小步数 ,接下来的每行输出一步的状态,如果在6步内无法达到目标状态,输出“No solution!”。

【输入输出样例】

输入文件名: 8num.in

283164705

123804765

输出文件名:8num.out

5

283

164

705

283104765

203184765

023184765

123084765

123804765

技术分享

【问题分析】:

  这是一道典型的搜索题目,搜索产生的结点可以达到9!,再加上判重,如果不优化的话,耗时严重,关于广搜得优化我们后面的学习中再作讨论,本题只要求输出6步以内可以达到的目标,所以使用一般的广搜即可解决。问题是,如何在扩展结点的同时计算出已经走的步数,而不是找到目标状态后再逆序跟踪输出步数和步骤

  两种方法,一种是在队列中增加一个域,来记录扩展出当前状态用的步数,该步数是由它的父节点步数加1得到。

  另一种方法是双尾指针法。广搜是按层次搜索的,每搜完一层,即可视为走完一步,所以,只要记录下来当前搜索了多少层即可。我们使用tail2记录当前扩展层最后一个节点在队列中的位置,当head指向tail2并且扩展完tail2,说明完成一层的搜索,此时step+1,并且tail2指向tail,也就是扩展出的新的一层的尾结点。

记录步数的广搜算法框架如下:

 1 Program Bfs; 
 2 初始化,初始状态存入OPEN 表; 
 3 队列首指针head:=0;尾指针 tail:=1tail2:=1; step:=1;
 4 repeat 
 5     指针head后移一位,指向待扩展结点; 
 6     for I=1 to max do     {max为产生子结点的规则数} 
 7     begin  
 8       if 子结点符合条件 then 
 9          begin 
10            if新结点是目标结点 then 输出 else
11              if新结点与原已产生结点不重复 then tail 指针增1,把新结点存入列尾; 
12          end; 
13     end; 
14  if head=tail2 then begin inc(step);tail2:=tail;end;
15 until(head>=tail);   {队列空}

另外我们需要考虑如何记录数码状态,可以使用3*3的二维数组,也可以使用长度为9的字符串。一般使用数组记录,实现起来比较简单,但是判重的时候比较麻烦,如果使用9维布尔数组来判重,那么需要很大的存储空间,不过速度会较快,如果使用字符串来记录,难以用布尔数组来判重,所以判重耗时巨大,但是字符串可以直接比较并且本题的规模也不大,只要判断6步以内是否能够达到目标状态,所以我们不妨使用字符串s来记录数码状态,用p来记录s中0的位置,0与其他数字的交换最多有四种情况:

与上方的数字交换则把p与p-3位置的字符交换位置;

与右边的数字交换则把p与p+1位置的字符交换位置;

与下方的数字交换则把p与p+3位置的字符交换位置;

与左边的数字交换则把p与p-1位置的字符交换位置;

注意特殊情况下,当p=4或7时,0不能与左边数字交换,当p=3或6时,0不能与右边数字交换,另外,所有的交换位置都不能超过1~9范围。

 

搜索算法_8数码难题1

AYYZOJ p1461

广度优先搜索(二)

标签:

原文地址:http://www.cnblogs.com/vacation/p/5184250.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!