1、= i;= pnti; end; write(Dep = ,n-1, : 1); for j := n-1 downto 1 do begin - ,qmsj); readln;end; f1 := 1城市1已到; qm1 := 1队列的第一个节点是1; pnt1 :没有父辈节点 closed : open := 1; repeat inc(closed); k := qmclosed; if k 6 then begin= fclosed; for i := 2 to 6 do if (not(i in fs) and (linkk,i 0) then begin inc(open); qm
2、open : fopen := fs+i; pntopen := closed; if i = 6 then print; until closed end.在广度优先搜索中,我们将扩展出来的结点存贮在一个称作qm的数组里,qm数组采用“先进先出”的队列结构,设两个指针closed和open,分别是队首指针和队尾指针。其中qm1.closed-1存贮已扩展的结点(即这些结点的子结点已扩展出);qmclosed.open存贮待扩展结点(即这些结点的子结点尚待扩展)。当closed = open则表示队列空,结束。pnt为父辈结点数组,它记录了每个结点的父辈结点,当找到目标后,可沿着父辈结点倒串上
3、去,输出路径方案。在广度优先搜索中,第一个达到目标结点的,即是最短路径。例 1-2-2 有一个由四个1和四个0,中间有一个空格组成的字符串1111 0000,现规定: 1只能向右运动,0只能向左运动。 空格左右的1或0可以移动,进入空格。 1可以跳过一个0,进入空格;0也可以跳过一个1,进入空格。 要求在符合上述规定的方式下,以最少的步骤,将其变为字符串0000 1111,编程打印输出运动的每一步。 a9 = string9; qt = record a : a9; x,pnt : qm : arraybyte of qt; temp : qt; closed,open :Procedure
4、print; Var buf : array1.30 of byte; i,j : begin j := 0 inc(j); bufj := qmi.pnt;= j downto 1 do beginNo.,i-j:2,qmbufi.a); halt;procedure comp; var i := 1 to open do if qmi.a = temp.a then exit;= open+1; qmopen.a := temp.a; qmopen.x := temp.x; qmopen.pnt : if temp.a = 0000 1111 then print;procedure op
5、a; with temp do if (x 1) and (ax-1 = 1) then begin ax-1 := ; ax : x := x-1; comp;procedure opb; if (x 9) and (ax+1 = 0 ax+1 := x+1;procedure opc; 2) and (ax-1 = ) and (ax-2 = ax-2 := x-2;procedure opd; 8) and (ax+1 = ) and (ax+2 = ax+2 := x+2; with qm1 do begin1111 0000= 5; pnt : while closed open d
6、o begin= closed+1; opa; opb; opc; opd;例 1-2-3 在魔方风靡全球后,Rubik先生发明了它的简化版魔板,如下图:魔板由6个同样大小的方块组成,每个方块的颜色均不相同,本题中用数字16分别表示,可能出现在魔板的任一位置。对魔板可施加三种不同的操作,分别以a、b、c标识,具体操作方法如下:应用三种基本操作,可由任一状态到达任意另一状态。编一程序,对于输入的一个初始状态和一个目标状态,寻找一种最少的操作步骤,打印输出从初始状态到目标状态的每一步操作和状态值。 x,y : integer; op : char; array1.720 of qt; closed
7、,open,k,l,m,n : array1.30 of integer;= j+1; sj : writeln(qm1.x); writeln(qm1.y); writeln;= j-1 downto 1 do begin writeln(Oprate :,qmsi.op); writeln(qmsi.x); writeln(qmsi.y);procedure comp(opx : char); if (m = qmi.x) and (n = qmi.y) then exit;= m; qmopen.y := n; qmopen.op := opx; if (m = k) and (n =
8、l) then print; m := qmclosed.y;= qmclosed.x; comp(a= (qmclosed.x mod 10)*100+(qmclosed.x div 10);= (qmclosed.y mod 10)*100+(qmclosed.y div 10);b a,b,c,d := qmclosed.x div 100; b := qmclosed.x mod 100 div 10; c := qmclosed.y div 100; d := qmclosed.y mod 100 div 10;= c*100+a*10+(qmclosed.x mod 10);= d
9、*100+b*10+(qmclosed.y mod 10);cInput Source M(1,2,3) : readln(qm1.x);Input Source N(6,5,4) : readln(qm1.y);Input Object K(1,2,3) : readln(k);Input Object L(6,5,4) : readln(l); qm1.pnt :例 1-2-4 八数码问题:在3*3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一个数字,棋盘上留有一个空格,空格周围的棋子可以移到空格中。要求给出一种初始状态和一种目标状态,找出一种最少步骤的移动方法,实现从初始状态到目标状
10、态的转变。例如: 初始状态 目标状态 2 8 3 1 2 3 1 6 4 8 4 7 5 7 6 5Type a33 = array1.3,1.3 of byte; a4 = array1.4 of -1.1; node = record ch : a33; y,x : word;Const start : a33 = (2,8,3),(1,6,4),(7,0,5); goal : a33 = (1,2,3),(8,0,4),(7,6,5); x1 = 2; y1 = 3; max = 4800; dx : a4 = (0,-1,0,1); dy : a4 = (-1,0,1,0);Var d
11、ata : array1.max of node; node; r,tx,ty :Function check(k : byte) : boolean; ty := temp.y+dyk; tx := temp.x+dxk; if (ty in 1.3) and (tx in 1.3) then check := true else check := false;Function dupe : j,k : inc(i);= true;= 1 to 3 do for k : if datai.chj,k = open-1); dupe := b;Function goals :Var i,j :
12、 goals : if dataopen.chi,j = open) or (open max-3);No solution !二、队列与广度优先搜索队列是不同于栈的另一种线性表。在日常生活中,无论是购物、订票或候车都有可能要排队。排队所遵循的原则是“先来先服务”,后来者总是加到队尾,排头者总是先离开队伍。队列就是从日常生活中的排队现象抽象出来的。所谓队列,就是允许在一端进行插入,在另一端进行删除的线性表。允许插入的一端称为队尾,通常用一个队尾指针open指向队尾元素,即open总是指向最后被插入的元素;允许删除的一端称为队首,通常也用一个队首指针closed指向排头元素的前面。初始时clos
13、ed=open=0(如图)。 显然,在队列这种数据结构中,最先插入在元素将是最先被删除;反之最后插入的元素将最后被删除,因此队列又称为“先进先出”(FIFOfirst in first out)的线性表。与栈相似,队列的顺序存储空间可以用一维数组q1m模拟: Q: 1 m 我们按照如下方式定义队列: M = 队列元素的上限; Equeue = array1.m of qtype; 队列的类型定义Var equeue; 队列open,closed : integer; 队尾指针和队首指针队列的运算主要有两种1.过程ADD(qm,x,open)在队列qm的尾端插入元素x procedure ADD
14、(var qm : equeue; qtype; var open : integer); if open = m then writeln(Overflow) 上溢 else begin 后移队尾指针并插入元素x= x; end;2.过程DEL(qm,y,closed,open)取出qm队列的队首元素y procedure DEL(var qm :var y :var closed,open : if closed = open then writeln(underflow) 下溢 else begin 后移队首指针并取出队首元素= closed+1;y := qmclosed;由于队列只能
15、在一端插入,在另一端删除,因此随着入队及出队运算的不断进行,就会出现一种有别于栈的情形:队列在数组中不断地向队尾方向移动,而在队首的前面产生一片不能利用的空闲存储区,最后会导致当尾指针指向数组最后一个位置(即open = m)而不能再加入元素时,存储空间的前部却有一片存储区无端浪费,这种现象称为“假溢出”。下图给出了一个“假溢出”的示例: m Openm Am“假溢出”A4open3 A3closed3 Closed 3 2A2 2 1 1A1Closed,open Closed 初始时队列空 加入三个元素 删除三个元素队列空 加入m-3个元素队列满closed=open=0 closed=0
16、 open=3 closed=open=3 closed=3 open=m 为了解决“假溢出”的问题,我们不妨作这样的设想:在队列中,当存储空间的最后一个位置已被使用而要进行入队运算时,只要存储空间第一个位置空闲,便可将元素加入到第一个位置,即将存储空间的第一个位置作为队尾。采用首尾相接的队列结构后,可以有效地解决假溢出的问题,避免数据元素的移动,这就是所谓的循环队列。下图给出了循环队列的结构。循环队列将队列存储空间的最后一个位置绕到第一个位置,形成逻辑上的环状空间,供队列循环使用,循环队列的存取方法亦为“先进先出”。对循环队列操作有以下几种状态:初始时队列空,队首指针和队尾指针均指向存储空间
17、的最后一个位置,即closed = open = m。 入队运算时,尾指针进一,即open := open+1;if open = m+1 then open := 1; 这两条语句可用一条语句替代:= open mod m + 1; 出队运算时,首指针进一,即if closed = m+1 then closed := closed mod m + 1; 队列空时有closed = open。 队列满时有closed = open mod m + 1。(为了区分队列空和队列满,改用“队尾指针追上队首指针” 这 一特征作为队列满标志。这种处理方法的缺点是浪费队列空间的一个存储单元)循环队列的运算有两种:1.过程ADD2(qm,x,open)在循环队列qm中插入一个新元素x procedure ADD2 (var qm : e
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1