广度(宽度)优先搜索l_第1页
广度(宽度)优先搜索l_第2页
广度(宽度)优先搜索l_第3页
广度(宽度)优先搜索l_第4页
广度(宽度)优先搜索l_第5页
已阅读5页,还剩37页未读 继续免费阅读

下载本文档

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

文档简介

1、广度(宽度)优先搜索广度(宽度)优先搜索深度搜索与广度搜索区分深度搜索与广度搜索区分深度搜索与广度搜索深度搜索与广度搜索深度搜索与广度搜索的区别:深度搜索下一次扩展的是本次扩展出来的子节点中的一个,而广度搜索扩展的则是本次扩展的节点的兄弟节点。在具体实现上为了提高效率,所以采用了不同的数据结构。广度搜索是求解最优解的一种较好的方法,而深度搜索多用于只要求解,并且解答树中的重复节点较多并且重复较难判断时使用,但往往可以用回溯算法代替。一些基本概念 节点:记录扩展的状态。 弧/边:记录扩展的路径。 搜索树:描述搜索扩展的整个过程。 节点的耗散值 令C(i,j)为从节点ni到nj的这段路径(或者弧)

2、的耗散值,一条路径的耗散值就等于连接这条路径各节点间所有弧的耗散值总和。可以用递归公式描述如下:C(ni ,t)= C(ni , nj)+ C(nj , t)4搜索树根节点叶 子 节点4,5,6,7,88123567广度优先搜索的过程广度优先搜索的过程 广度优先搜索算法(又称宽度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。 广度优先算法的核心思想是:从初始节点开始,应用算符生成第一层节点,检查目标节点是否在这些后继节点中,若没有,再用产生式规则将所有第一层的节点逐一扩展,得

3、到第二层节点,并逐一检查第二层节点中是否包含目标节点。若没有,再用算符逐一扩展第二层的所有节点,如此依次扩展,检查下去,直到发现目标节点为止。即 从图中的某一顶点V0开始,先访问V0; 访问所有与V0相邻接的顶点V1,V2,.,Vt; 依次访问与V1,V2,.,Vt相邻接的所有未曾访问过的顶点; 循此以往,直至所有的顶点都被访问过为止。 这种搜索的次序体现沿层次向横向扩长的趋势,所以称之为广度优先搜索。广度搜索策略广度搜索策略 综合数据库(变量设置) 与问题相关的所有数据元素构成的集合 ,用来表述问题状态或有关事实 。 产生式规则 构建了综合数据库以后,还需要研究问题的移动规则,称为产生式规则

4、。 搜索策略 搜索策略的实质是确定如何选取规则的方式。有两种基本方式:一种是不考虑给定问题所具有的特定知识,系统根据事先确定好某种固定顺序,依次调用规则或随机调用规则,这实际上是盲目搜索的方法。另一种是考虑问题领域可应用的知识,动态地确定规则的排列次序,优先调用较合适的规则使用,这就是通常所说的启发式搜索策略。广度优先搜索算法描述:广度优先搜索算法描述:Program bfs;初始化,初始状态存入队列;队列首指针head:=0; 尾指针tail:=1;repeat 指针head后移一位,指向待扩展结点; for i:=1 to max do begin /max为产生子结点的规则数 if 子结

5、点符合条件 then begin tail指针增1,把新结点存入列尾; if新结点与原已产生结点重复then删去该结点(取消入队,tail减1) else if新结点是目标结点then输出并退出; end; end;until(head=tail); /队列为空广度优先搜索注意事项广度优先搜索注意事项 1、每生成一个子结点,就要提供指向它们父亲结点的指针。当解出现时候,通过逆向跟踪,找到从根结点到目标结点的一条路径。当然不要求输出路径,就没必要记父亲。 2、生成的结点要与前面所有已经产生结点比较,以免出现重复结点,浪费时间,还有可能陷入死循环。 3、如果目标结点的深度与“费用”(如:路径长度)

6、成正比,那么,找到的第一个解即为最优解,这时,搜索速度比深度搜索要快些,在求最优解时往往采用广度优先搜索;如果结点的“费用”不与深度成正比时,第一次找到的解不一定是最优解。 4、广度优先搜索的效率还有赖于目标结点所在位置情况,如果目标结点深度处于较深层时,需搜索的结点数基本上以指数增长。八数码问题八数码问题 在3*3组成的九宫格棋盘上,摆有八个将牌,每一个将牌都刻有18中的某一个数码。棋盘中留有一个空格,允许其周围的某一个将牌向空格中移动,如图1所示。这样通过移动将牌就可以不断改变的布局结构,给出一个初始布局(称初始状态)和一个目标布局(称目标状态),问如何移动将牌,才能实现从初始状态到目标状

7、态的转换。 下面我们看看怎样用宽度优先搜索来解决八数码问题。 图2给出广度优先搜索应用于八数码难题时所生成的搜索树。搜索树上的所有结点都标记它们所对应的状态,每个结点旁边的数字表示结点扩展的顺序。粗线条路径表明求得的一个解。从图中可以看出,扩展第个结点,总共生成个结点之后,才求得这个解。此外,直接观察此图表明,不存在有更短走步序列的解。八数码问题扩展搜索树八数码问题扩展搜索树 综合数据库(变量设置)Pxy,其中1=x,y=1 then begin Pm, n:=Pm,n -1 ; Pm,n -1 :=0 end; if m - 1=1 then begin Pm, n:=Pm-1, n ; P

8、m-1, n :=0 end; if n + 1=3 then begin Pm, n:=Pm, n+1; Pm, n+1:=0 end; if m + 1=3 then begin Pm, n:=Pm+1,n; Pm+1, n:=0 end;Const Dir : array1.4,1.2of longint 对应四种产生式规则 = (1,0),(1,0),(0,1),(0,1);控制策略 PROCEDURE Production-System; DATA初始化数据库 Repeat 在规则集中选择某一条可作用于DATA的规则R DATAR作用于DATA后得到的结果 Until DATA满足结

9、束条件八数码问题宽度优先算法框架List1=source;closed:=0;open:=1; 加入初始节点,List为扩展节点的表Repeat closed:=closed+1; n:=Listclosed; 取出closed对应的节点 For x:=1 to 4 do begin new:=move(n,4); 对n节点使用第x条规则,得到new if not_appear(new,List) then begin 如果new没有在List中出现 open:=open+1;Listopen:=new;加入新节点到open Listopen.Father:=closed; 修改指针 if L

10、istopen=Goal then GetOut; end; enduntil closed 0) and ( X 0 ) and ( Y 4 ) then begin ok:=false;exit end; OK:=true;Function Same(A,B : T8no):Boolean; 判断判断A,B状态是否相等状态是否相等 Var i,j : integer; Begin Same:=false; For i:=1 to 3 do for j:=1 to 3 do if Ai,jBi,j then exit; Same:=true; End;new.State:=n.State;

11、new=Expand(n,d) new.StateX,Y:=0; new.Staten.x0,n.y0:=n.StateX,Y; new.X0:=X;new.Y0:=Y; end; procedure Add(new : tList); 插入节点插入节点new begin if not_Appear(new) then Begin 如果如果new没有在没有在List出现出现 Inc(open); new加入加入open表表 Listopen := new; end; end; procedure Expand(Index : integer; var n : tList); 扩展扩展n的子节点

12、的子节点 var i : integer; new : tList; OK : boolean; Begin if Same(n.State , Target) then begin 如果找到解如果找到解 Found := true; Best :=n.Dep; Answer:=Index; Exit; end; For i := 1 to 4 do begin 依次使用条规则依次使用条规则 Move(n,i,OK,new); if not ok then continue;new.Father := Index; new.Dep :=n.dep + 1; Add(new); end; end

13、; procedure GetOutInfo; 输出输出 procedure Outlook(Index : integer); 递归输出每一个解递归输出每一个解 var i,j : integer; begin if Index=0 then exit; Outlook(ListIndex.Father); with ListIndex do for i:=1 to 3 do begin for j:=1 to 3 do write(Statei,j, ); writeln; end; writeln; end; begin Writeln(Total = ,Best); Outlook(A

14、nswer); end; procedure Main; 搜索主过程搜索主过程 begin Repeat Inc(Closed); Expand(Closed,ListClosed); 扩展扩展Closed Until (Closed=open) or Found; if Found then GetOutInfo 存在解存在解 else Writeln(no answer); 无解无解 end;begin Assign(Input,input.txt);ReSet(Input); Assign(Output,Output.txt);ReWrite(Output); GetInfo; Init

15、ialize; Main; Close(Input);Close(Output);End.【例例1】图4表示的是从城市A到城市H的交通图。从图中可以看出,从城市A到城市H要经过若干个城市。现要找出一条经过城市最少的一条路线。【算法分析算法分析】看到这图很容易想到用邻接距阵来表示,0表示能走,1表示不能走。如图。 首先想到的是用队列的思想。a数组是存储扩展结点的队列,ai.city记录经过的城市,ai.pre记录前趋城市,这样就可以倒推出最短线路。具体过程如下:(1) 将城市A入队,队首为0、队尾为1。(2) 将队首所指的城市所有可直通的城市入队(如果这个城市在队列中出现 过就不入队,可用一个集

16、合来判断),将入队城市的pre指向队首的位置。然后将队首加1,得到新的队首城市。重复以上步骤,直到搜到城市H时,搜索结束。利用pre可倒推出最少城市线路。【参考程序参考程序】Program Ex8_1;const ju:array1.8,1.8 of 0.1=(1,0,0,0,1,0,1,1), (0,1,1,1,1,0,1,1), (0,1,1,0,0,1,1,1), (0,1,0,1,1,1,0,1), (1,1,0,1,1,1,0,0), (0,0,1,1,1,1,1,0), (1,1,1,0,0,1,1,0), (1,1,1,1,0,0,0,1);type node=record /记

17、录定义记录定义 city: char; pre: integer;end;var head,tail,i:integer; a:array 1.100 of node; s:set of A.H;procedure out(d:integer); /输出过程输出过程begin write(ad.city); repeat d:=ad.pre; write(-,ad.city); until ad.pre=0; writeln;end;procedure doit;begin head:=0; tail:=1; a1.city:=A; a1.pre:=0; s:=A; repeat /步骤步骤2

18、 inc(head); /队首加一,出队队首加一,出队 for i:=1 to 8 do /搜索可直通的城市搜索可直通的城市if (juord(ahead.city)-64,i=0)and (not(chr(i+64) in s)then begin /判断城市是否走过判断城市是否走过 inc(tail); /队尾加一,入队队尾加一,入队 atail.city:=chr(64+i); atail.pre:=head; s:=s+atail.city; if atail.city=H then begin outtail;break;end;end;until head=tail;end;BEG

19、IN /主程序主程序doit;END.输出:输出:H-F-A【例例2】一矩形阵列由数字0到9组成,数字1到9代表细胞,细胞的定义为沿细胞数字上下左右还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。如:阵列 4 100234500067103456050020456006710000000089有4个细胞。【算法分析算法分析】 从文件中读入m*n矩阵阵列,将其转换为boolean矩阵存入bz数组中; 沿bz数组矩阵从上到下,从左到右,找到遇到的第一个细胞; 将细胞的位置入队h,并沿其上、下、左、右四个方向上的细胞位置入队,入队后的位置bz数组置为FLASE;将h队的队头出队,沿其上、下、左、

20、右四个方向上的细胞位置入队,入队后的位置bz数组置为FLASE; 重复4,直至h队空为止,则此时找出了一个细胞; 重复2,直至矩阵找不到细胞; 输出找到的细胞数。program Ex8_2;const dx:array1.4 of 1.1=(1,0,1,0); dy:array1.4 of 1.1=(0,1,0,1);var name,s:string; pic:array1.50,1.79 of integer; bz:array1.50,1.79 of boolean; m,n,i,j,num:integer; h:array1.4000,1.2 of integer;procedure

21、doit(p,q:integer);var i,t,w,x,y:integer;begin inc(num);bzp,q:=false; t:=1;w:=1;h1,1:=p;h1,2:=q; /遇到的第一个细胞入队 repeat for i:=1 to 4 do /沿细胞的上下左右四个方向搜索细胞 begin x:=ht,1+dxi;y:=ht,2+dyi; if (x0) and (x0) and (yw; /直至队空为止end;begin fillchar(bz,sizeof(bz),true); num:=0; readln(m,n); for i:=1 to m do begin re

22、adln(s); for j:=1 to n do begin pici,j:=ord(sj)ord(0); if pici,j=0 then bzi,j:=false; end; end; for i:=1 to m do for j:=1 to n do if bzi,j then doit(i,j); /在矩阵中寻找细胞 writeln(NUMBER of cells=,num); readln;end.【例例3】最短路径(1995年高中组第4 题)如下图所示,从入口(1)到出口(17)的可行路线图中,数字标号表示关卡。现将上面的路线图,按记录结构存储如下图6: 请设计一种能从存储数据中

23、求出从入口到出口经过最少关卡路径的算法。【算法分析算法分析】 该题是一个路径搜索问题,根据图示,从入口(1)到出口(17)可能有多条途径,其中最短的路径只有一条,那么如何找最短路径呢?根据题意,用数组NO存储各关卡号,用数组PRE存储访问到某关卡号的前趋关卡号。其实本题是一个典型的图的遍历问题,我们可以采用图的广度优先遍历,并利用队列的方式存储顶点之间的联系。从入口(1)开始先把它入队,然后把(1)的所有关联顶点都入队,即访问一个顶点,将其后继顶点入队,并存储它的前趋顶点,直到访问到出口(17)。最后,再从出口的关卡号(17)开始回访它的前趋关卡号,直到入口的关卡号(1),则回访的搜索路径便是

24、最短路径。从列表中可以看出出口关卡号(17)的被访问路径最短的是: (17) (16)(19)(18)(1) 由此,我们得到广度优先遍历求最短路径的基本方法如下: 假设用邻接矩阵存放路线图(aI,j=1表示I与j连通,aI,j=0表示I与j不连通)。 再设一个队列和一个表示拓展到哪个顶点的指针变量pos。 (1)从入口开始,先把(1)入队,并且根据邻接矩阵,把(1)的后继顶点全部入队,并存储这些后继顶点的前趋顶点为(1);再把pos后移一个,继续拓展它,将其后继顶点入队,并存储它们的前趋顶点,直到拓展到出口(目的地(17); 注意后继顶点入队前,必须要检查这个顶点是否已在队列中,如果已经在了就

25、不要入队了;这一步可称为图的遍历或拓展; (2)从队列的最后一个关卡号(出口(17)开始,依次回访它的前驱顶点,倒推所得到的路径即为最短路径。主要是依据每个顶点的前趋顶点倒推得到的。实现如下: I:=1 ; WHILE NOI 17 DO I:=I+1 ; REPEAT WRITE(,NOI,); WRITE(); I:=PREI ; UNTIL I=0;【参考程序】留给同学们完成,文件名ex8_3.pas。【例例4】迷宫问题迷宫问题 如下图所示,给出一个N*M的迷宫图和一个入口、一个出口。 编一个程序,打印一条从迷宫入口到出口的路径。这里黑色方块的单元表示走不通(用1表示),白色方块的单元表

26、示可以走(用0表示)。只能往上、下、左、右四个方向走。如果无路则输出“no way.”。入口0-1000000-10000-1000-1-100000-1-1-100-1-100000 出口0000000-1-1【算法分析算法分析】只要输出一条路径即可,所以是一个经典的回溯算法问题,本例给出了回溯(深搜)程序和广搜程序。实现见参考程序。【深搜参考程序深搜参考程序】program EX8_4_1;const maxn=50;var map:array 1.maxn,1.maxn of integer; f:boolean; n,m,i,j,desx,desy,soux,souy,totstep:

27、integer; route:array1.maxn of record x,y : integer; end; procedure move(x,y,step:integer);begin mapx,y:=step; /走一步,作标记,把步数记下来 routestep.x := x; routestep.y:= y; /记路径 if (x=desx) and (y=desy) then begin f:=true; totstep:=step; end else begin if (ym) and (mapx,y+1=0) then move (x,y+1,step+1); /向右 if n

28、ot f and (xn)and(mapx+1,y=0) then move(x+1,y ,step+1); /往下 if not f and (y1)and(mapx,y1=0) then move(x,y1, step+1); /往左 if not f and (x1)and(mapx1,y=0) then move(x1,y, step+1); /往上 end;end;BEGIN readln(n,m); /n行m列的迷宫 for i:=1 to n do /读入迷宫,0表示通,1表示不通 begin for j:=1 to m do read(mapi,j); readln; end;

29、 write(input the enter:); readln(soux,souy); /入口 write(input the exit:); readln(desx,desy); /出口 f:=false; /f=false表示无解;f=true表示找到了一个解 move(soux,souy,1); if f then for i:=1 to totstep do /输出直迷宫的路径 write(routei:4); else writeln (no way.);END.【广搜参考程序广搜参考程序】program EX8_4_2;const maxn=50; u:array1.4 of i

30、nteger=(0,1,0,-1); w:array1.4 of integer=(1,0,-1,0);var map:array 1.maxn,1.maxn of integer; f:boolean; n,m,i,j,desx,desy,soux,souy,head,tail,x,y:integer; route:array1.maxn of record x,y,pre : integer; end;procedure print(d:integer);begin if routed.pre0 then print(routed.pre); write(,routed.x,routed.

31、y,);end;BEGIN readln(n,m); /n行行m列的迷宫列的迷宫 for i:=1 to n do /读入迷宫,读入迷宫,0表示通,表示通,-1表示不通表示不通 begin for j:=1 to m do read(mapi,j); readln; end; write(input the enter:); readln(soux,souy); /入口入口 write(input the exit:); readln(desx,desy); /出口出口 head:=0; tail:=1; f:=false; mapsoux,souy:=-1; routetail.x:=sou

32、x; routetail.y:=souy; routetail.pre:=0; while headtail do /队列不为空队列不为空 begin inc(head); for i:=1 to 4 do /4个方向个方向 begin x:=routehead.x+ui; y:=routehead.y+wi; if (x0)and(x0)and(y=m)and(mapx,y=0) then begin /本方向上可以走本方向上可以走 inc(tail); routetail.x:=x; routetail.y:=y; routetail.pre:=head; mapx,y:=-1; if (

33、x=desx)and(y=desy) then /扩展出的结点为目标结点扩展出的结点为目标结点 begin f:=true; print(tail); break; end; end; end; if f then break; end; if not f then writeln(no way!);END.输入输入1 1:输出输出1 1:输入输入2 2:输出输出2 2:8 58 5-1 -1 -1 -1 -1-1 -1 -1 -1 -1 0 0 0 0 -1 0 0 0 0 -1-1 -1 -1 0 -1-1 -1 -1 0 -1-1 0 0 0 -1-1 0 0 0 -1-1 0 0 -1

34、 -1-1 0 0 -1 -1-1 0 0 0 -1-1 0 0 0 -1-1 -1 -1 0 -1-1 -1 -1 0 -1-1 0 0 0 -1-1 0 0 0 -12 12 18 48 4 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 1 2 3 4 -1 1 2 3 4 -1 -1 -1 -1 5 -1 -1 -1 -1 5 -1 -1 0 7 6 -1 -1 0 7 6 -1 -1 0 8 -1 -1 -1 0 8 -1 -1 -1 0 9 10 -1 -1 0 9 10 -1 -1 -1 -1 11 -1 -1 -1 -1 11 -1 -1 0 0 12 -1 -1

35、0 0 12 -18 58 5-1 -1 -1 -1 -1-1 -1 -1 -1 -1 0 0 0 0 -1 0 0 0 0 -1-1 -1 -1 0 -1-1 -1 -1 0 -1-1 0 0 0 -1-1 0 0 0 -1-1 0 0 -1 -1-1 0 0 -1 -1-1 0 0 0 -1-1 0 0 0 -1-1 -1 -1 -1 -1-1 -1 -1 -1 -1-1 0 0 0 -1-1 0 0 0 -12 12 18 48 4no way.no way.【上机练习上机练习】1、编程计算由“*”号围成的下列图形的面积。面积计算方法是统计*号所围成的闭合曲线中水平线和垂直线交点的数目。

36、如下图所示,在10*10的二维数组中,有“*”围住了15个点,因此面积为15。0 0 0 0 0 0 0 0 0 00 0 0 0 * * * 0 0 00 0 0 0 * 0 0 * 0 00 0 0 0 0 * 0 0 * 00 0 * 0 0 0 * 0 * 00 * 0 * 0 * 0 0 * 00 * 0 0 * * 0 * * 00 0 * 0 0 0 0 * 0 00 0 0 * * * * * 0 00 0 0 0 0 0 0 0 0 0【样例输入样例输入】area.in0 0 0 0 0 0 0 0 0 00 0 0 0 1 1 1 0 0 00 0 0 0 1 0 0 1

37、0 00 0 0 0 0 1 0 0 1 00 0 1 0 0 0 1 0 1 00 1 0 1 0 1 0 0 1 00 1 0 0 1 1 0 1 1 00 0 1 0 0 0 0 1 0 00 0 0 1 1 1 1 1 0 00 0 0 0 0 0 0 0 0 0【样例输出样例输出】area.out 152、细胞、细胞(cell.pas)【问题描述问题描述】 一矩形阵列由数字0到9组成,数字1到9代表细胞,细胞的定义为沿细胞数字上下左右还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。如阵列: 0234500067103456050020456006710000000089有4个细胞。【输入格式输入格式】整数m,n(m行,n列)矩阵【输出格式输出格式】细胞的个数

温馨提示

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

评论

0/150

提交评论