广度搜索文档格式.docx
《广度搜索文档格式.docx》由会员分享,可在线阅读,更多相关《广度搜索文档格式.docx(18页珍藏版)》请在冰豆网上搜索。
=i;
=pnt[i];
end;
write('
Dep='
n-1,'
:
1'
);
forj:
=n-1downto1dobegin
->
'
qm[s[j]]);
readln;
end;
f[1]:
=[1]{城市1已到};
qm[1]:
=1{队列的第一个节点是1};
pnt[1]:
{没有父辈节点}
closed:
open:
=1;
repeat
inc(closed);
k:
=qm[closed];
ifk<
>
6thenbegin
=f[closed];
fori:
=2to6do
if(not(iinfs))and(link[k,i]>
0)thenbegin
inc(open);
qm[open]:
f[open]:
=fs+[i];
pnt[open]:
=closed;
ifi=6thenprint;
untilclosed>
end.
在广度优先搜索中,我们将扩展出来的结点存贮在一个称作qm的数组里,qm数组采用“先进先出”的队列结构,设两个指针closed和open,分别是队首指针和队尾指针。
其中qm[1..closed-1]存贮已扩展的结点(即这些结点的子结点已扩展出);
qm[closed..open]存贮待扩展结点(即这些结点的子结点尚待扩展)。
当closed>
=open则表示队列空,结束。
pnt为父辈结点数组,它记录了每个结点的父辈结点,当找到目标后,可沿着父辈结点倒串上去,输出路径方案。
在广度优先搜索中,第一个达到目标结点的,即是最短路径。
例1-2-2有一个由四个1和四个0,中间有一个空格组成的字符串‘11110000’,现规定:
①1只能向右运动,0只能向左运动。
②空格左右的1或0可以移动,进入空格。
③1可以跳过一个0,进入空格;
0也可以跳过一个1,进入空格。
要求在符合上述规定的方式下,以最少的步骤,将其变为字符串‘00001111’,编程打印输出运动的每一步。
a9=string[9];
qt=record
a:
a9;
x,pnt:
qm:
array[byte]ofqt;
temp:
qt;
closed,open:
Procedureprint;
Var
buf:
array[1..30]ofbyte;
i,j:
begin
j:
=0
inc(j);
buf[j]:
=qm[i].pnt;
=jdownto1dobegin
No.'
i-j:
2,'
qm[buf[i]].a);
halt;
procedurecomp;
vari:
=1toopendo
ifqm[i].a=temp.athenexit;
=open+1;
qm[open].a:
=temp.a;
qm[open].x:
=temp.x;
qm[open].pnt:
iftemp.a='
00001111'
thenprint;
procedureopa;
withtempdo
if(x>
1)and(a[x-1]='
1'
)thenbegin
a[x-1]:
='
;
a[x]:
x:
=x-1;
comp;
procedureopb;
if(x<
9)and(a[x+1]='
0'
a[x+1]:
=x+1;
procedureopc;
2)and(a[x-1]='
)and(a[x-2]='
a[x-2]:
=x-2;
procedureopd;
8)and(a[x+1]='
)and(a[x+2]='
a[x+2]:
=x+2;
withqm[1]dobegin
11110000'
=5;
pnt:
whileclosed<
opendobegin
=closed+1;
opa;
opb;
opc;
opd;
例1-2-3在魔方风靡全球后,Rubik先生发明了它的简化版——魔板,如下图:
魔板由6个同样大小的方块组成,每个方块的颜色均不相同,本题中用数字1–6分别表示,可能出现在魔板的任一位置。
对魔板可施加三种不同的操作,分别以a、b、c标识,具体操作方法如下:
应用三种基本操作,可由任一状态到达任意另一状态。
编一程序,对于输入的一个初始状态和一个目标状态,寻找一种最少的操作步骤,打印输出从初始状态到目标状态的每一步操作和状态值。
x,y:
integer;
op:
char;
array[1..720]ofqt;
closed,open,k,l,m,n:
array[1..30]ofinteger;
=j+1;
s[j]:
writeln(qm[1].x);
writeln(qm[1].y);
writeln;
=j-1downto1dobegin
writeln('
Oprate:
qm[s[i]].op);
writeln(qm[s[i]].x);
writeln(qm[s[i]].y);
procedurecomp(opx:
char);
if(m=qm[i].x)and(n=qm[i].y)thenexit;
=m;
qm[open].y:
=n;
qm[open].op:
=opx;
if(m=k)and(n=l)thenprint;
m:
=qm[closed].y;
=qm[closed].x;
comp('
a'
=(qm[closed].xmod10)*100+(qm[closed].xdiv10);
=(qm[closed].ymod10)*100+(qm[closed].ydiv10);
b'
a,b,c,d:
=qm[closed].xdiv100;
b:
=qm[closed].xmod100div10;
c:
=qm[closed].ydiv100;
d:
=qm[closed].ymod100div10;
=c*100+a*10+(qm[closed].xmod10);
=d*100+b*10+(qm[closed].ymod10);
c'
InputSourceM(1,2,3):
readln(qm[1].x);
InputSourceN(6,5,4):
readln(qm[1].y);
InputObjectK(1,2,3):
readln(k);
InputObjectL(6,5,4):
readln(l);
qm[1].pnt:
例1-2-4八数码问题:
在3*3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一个数字,棋盘上留有一个空格,空格周围的棋子可以移到空格中。
要求给出一种初始状态和一种目标状态,找出一种最少步骤的移动方法,实现从初始状态到目标状态的转变。
例如:
初始状态目标状态
283123
16484
75765
Type
a33=array[1..3,1..3]ofbyte;
a4=array[1..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
data:
array[1..max]ofnode;
node;
r,tx,ty:
Functioncheck(k:
byte):
boolean;
ty:
=temp.y+dy[k];
tx:
=temp.x+dx[k];
if(tyin[1..3])and(txin[1..3])
thencheck:
=true
elsecheck:
=false;
Functiondupe:
j,k:
inc(i);
=true;
=1to3do
fork:
ifdata[i].ch[j,k]<
data[open].ch[j,k]thenb:
untilbor(i>
=open-1);
dupe:
=b;
Functiongoals:
Vari,j:
goals:
ifdata[open].ch[i,j]<
goal[i,j]thenexit;
Proceduretrace;
closed='
closed,'
open='
open,'
oprater='
r);
=1to3dobegin
ifdata[open].ch[i,j]=0thenwrite('
)
elsewrite(data[open].ch[i,j]);
writeln
array[1..20]ofword;
k,n:
inc(n);
b[n]:
=data[i].pnt;
Staps:
n-1:
5);
=ndownto1dobegin
ifdata[b[k]].ch[i,j]=0
thenwrite('
elsewrite(data[b[k]].ch[i,j]);
withdata[1]dobegin
=start;
y:
=y1;
=x1;
=data[closed];
forr:
=1to4do
ifcheck(r)thenbegin
data[open]:
=temp;
withdata[open]dobegin
ch[y,x]:
=ch[ty,tx];
ch[ty,tx]:
=ty;
=tx;
{trace;
}
ifdupethendec(open)
elseifgoalsthenprint;
until(closed>
=open)or(open>
max-3);
Nosolution!
'
二、队列与广度优先搜索
队列是不同于栈的另一种线性表。
在日常生活中,无论是购物、订票或候车都有可能要排队。
排队所遵循的原则是“先来先服务”,后来者总是加到队尾,排头者总是先离开队伍。
队列就是从日常生活中的排队现象抽象出来的。
所谓队列,就是允许在一端进行插入,在另一端进行删除的线性表。
允许插入的一端称为队尾,通常用一个队尾指针open指向队尾元素,即open总是指向最后被插入的元素;
允许删除的一端称为队首,通常也用一个队首指针closed指向排头元素的前面。
初始时closed=open=0(如图)。
显然,在队列这种数据结构中,最先插入在元素将是最先被删除;
反之最后插入的元素将最后被删除,因此队列又称为“先进先出”(FIFO—firstinfirstout)的线性表。
与栈相似,队列的顺序存储空间可以用一维数组q[1‥m]模拟:
Q:
1m
我们按照如下方式定义队列:
M=队列元素的上限;
Equeue=array[1..m]ofqtype;
{队列的类型定义}
Var
equeue;
{队列}
open,closed:
integer;
{队尾指针和队首指针}
队列的运算主要有两种
1.过程ADD(qm,x,open)—在队列qm的尾端插入元素x
procedureADD(varqm:
equeue;
qtype;
varopen:
integer);
ifopen=m
thenwriteln(‘Overflow’){上溢}
elsebegin{后移队尾指针并插入元素x}
=x;
end;
2.过程DEL(qm,y,closed,open)—取出qm队列的队首元素y
procedureDEL(varqm:
vary:
varclosed,open:
ifclosed=open
thenwriteln(‘underflow’){下溢}
elsebegin{后移队首指针并取出队首元素}
=closed+1;
y:
=qm[closed];
由于队列只能在一端插入,在另一端删除,因此随着入队及出队运算的不断进行,就会出现一种有别于栈的情形:
队列在数组中不断地向队尾方向移动,而在队首的前面产生一片不能利用的空闲存储区,最后会导致当尾指针指向数组最后一个位置(即open=m)而不能再加入元素时,存储空间的前部却有一片存储区无端浪费,这种现象称为“假溢出”。
下图给出了一个“假溢出”的示例:
m
Open→m
Am
“假溢出”
A4
open→3
A3
closed→3
Closed→3
2
A2
2
1
1
A1
Closed,open→Closed→
初始时队列空加入三个元素删除三个元素队列空加入m-3个元素队列满
closed=open=0closed=0open=3closed=open=3closed=3open=m
为了解决“假溢出”的问题,我们不妨作这样的设想:
在队列中,当存储空间的最后一个位置已被使用而要进行入队运算时,只要存储空间第一个位置空闲,便可将元素加入到第一个位置,即将存储空间的第一个位置作为队尾。
采用首尾相接的队列结构后,可以有效地解决假溢出的问题,避免数据元素的移动,这就是所谓的循环队列。
下图给出了循环队列的结构。
循环队列将队列存储空间的最后一个位置绕到第一个位置,形成逻辑上的环状空间,供队列循环使用,循环队列的存取方法亦为“先进先出”。
对循环队列操作有以下几种状态:
初始时队列空,队首指针和队尾指针均指向存储空间的最后一个位置,
即closed=open=m。
●入队运算时,尾指针进一,即
open:
=open+1;
ifopen=m+1thenopen:
=1;
这两条语句可用一条语句替代:
=openmodm+1;
●出队运算时,首指针进一,即
ifclosed=m+1thenclosed:
=closedmodm+1;
●队列空时有closed=open。
●队列满时有closed=openmodm+1。
(为了区分队列空和队列满,改用“队尾指针追上队首指针”这一特征作为队列满标志。
这种处理方法的缺点是浪费队列空间的一个存储单元)
循环队列的运算有两种:
1.过程ADD2(qm,x,open)—在循环队列qm中插入一个新元素x
procedureADD2(varqm:
e