广度优先搜索 实例

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

广度优先搜索实例

【例题】八数码难题(Eight-puzzle)。在3X3的棋盘上,摆有 8个棋子,在每个棋子上标有1~8中的某一数字。棋盘中留有一个空格。空格周围的棋子可以移到空格中。要求解的问题是,给出一种初始布局(初始状态)和目标布局(目标状态),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。初始状态和目标状态如下:

初始状态目标状态 2 8 3 1 2 3 1 6 4 8 4 7 5 7 6 5

求解本题我们可以分3步进行。

问题分析:

由的解于题目要找是达到目标的最少步骤,因此可以这样来设计解题的方法:

初始状态为搜索的出发点,把移动一步后的布局全部找到,检查是否有达到目标的布局,如果没有,再从这些移动一步的布局出发,找出移动两步后的所有布局,再判断是否有达到目标的。依此类推,一直到某布局为目标状态为止,输出结果。由于是按移动步数从少到多产生新布局的,所以找到的第一个目标一定是移动步数最少的一个,也就是最优解。

建立产生式系统:

(1) 综合数据库。用3X3的二维数组来表示棋盘的布局比较直观。我们用Ch[i,j]表示第i 行第j列格子上放的棋子数字,空格则用0来表示。为了编程方便,还需存储下面3个数据:该布局的空格位置(Si,Sj);初始布局到该布局的步数,即深度dep;以及该布局的上一布局,即父结点的位置(pnt)。这样数据库每一个元素应该是由上述几个数据组成的记录。

在程序中,定义组成数据库元素的记录型为:

Type

node=record

ch:array[1..3,1..3] of byte;{存放某种棋盘布局}

si,sj:byte; {记录此布局中空格位置}

dep,pnt:byte;

end;

因为新产生的结点深度(从初始布局到该结点的步数)一般要比数据库中原有的结点深度大(或相等)。按广度优先搜索的算法,深度大(步数多)的结点后扩展,所以新产生的结点应放在数据库的后面。而当前扩展的结点从数据库前面选取,即处理时是按结点产生的先后次序进行扩展。这样广度优先搜索的数据库结构采用队列的结构形式较合适。我们用记录数组data来表示数据库,并设置两个指针:Head为队列的首指针,tail为队列的尾指针。(2) 产生规则。原规则规定空格周围的棋子可以向空格移动。但如果换一种角度观察,也可看作空格向上、下、左、右4个位置移动,这样处理更便于编程。设空格位置在(Si,sj),则有4条规则:

①空格向上移动: if si-1>=1 then ch[si,sj]:=ch[si-1,sj];ch[si-1,sj]:=0

②空格向下移动: if si+1<=3 then [si,sj]:=ch[si+1,sj];ch[si+1,sj]:=0

③空格向左移动: if sj-1<=1 then [si,sj]:=ch[si,sj-1];ch[si,sj-1]:=0

④空格向右移动: if sj+1<=3 then [si,sj]:=ch[si,sj+1];ch[si,sj+1]:=0

我们用数组Di和Dj来表示移动时行列的增量,移动后新空格的位置可表示为:

nx:=si+di(r)

ny:=sj+dj(r)

其中,r=1,2,3,4为空格移动方向,且 r 1 2 3 4 方向左上右下 di 0 -1 0 1 dj -1 0 1 0

(3) 搜索策略。按照问题分析中提出的方法,算法设计如下:

program num8;

程序中新布局与队列中已有布局是否重复,用dup函数检查;找到目标结点后,print过程负责打印出从初始态到目标态移动时各步的布局,buf[n)是用来存放待输出的布局在队列中

的位置。

procedure print;

根据上述算法编制的程序如下:program num8_str1;

uses Crt;

type a33:array[1..3,1..3] Of byte;

{3X3的二维数组,用于存放棋盘布局}

a4=array[1..4] of shortint;

node=record {定义数据库中每个元素记录类型结构}

ch: a33;

si, sj: byte;

pnt, dep: byte;

end;

const goal:a33 = ((1,2,3), (8,0,4), (7,6,5)); {目标布局}

start:a33 =((2,8,3), (1,6,4), (7,0,5)); {初始布局}

di:a4=(0,-1, 0, 1);

dj:a4=(-1, 0, 1, 0);

var data:array[1..100] of node;

temp: node;

r, k, ni, nj, Head, Tail, depth: integer;

{变量depth存放当前搜索深度}

function check(k: integer) :boolean; { 检查某步移动是否可行} begin

hi:=temp.si+di[k] ; nj:=temp.sj+dj[k];

if (ni in [1..3]) and (nj in [1..3]) {~移动后新位置仍在棋盘中} then check:=true else check:= false;

end;

function dupe: boolean; { 检查队尾新存入布局是否已在队列中存在} var i,j, k: integer;

buf:boolean;

Begin

buf:= false; i: = 0;

{变量将i依次指向队列中的各个布局(最后一个除外)的位置}

repeat

inc(i) ;buf:= true;

for j:=1 to 3 do

for k:=1 to 3 do

if data[i].ch[j,k] < >data[tail].ch[j,k]

{data[tail]是队列中最后一个元素,即新产生的布局}

then bur:= false;

until buf or (i> = tail-1);

{buf=truee新布局与队列中布局有重复}

dupe:= buf

相关文档
最新文档