请输入您要查询的百科知识:

 

词条 双向宽搜算法
释义

双向广度优先搜索算法

广度双向搜索的概念

所谓双向搜索指的是搜索沿两个力向同时进行:正向搜索:从初始结点向目标结点方向搜索;逆向搜索:从目标结点向初始结点方向搜索;当两个方向的搜索生成同一子结点时终止此搜索过程。

广度双向搜索算法

广度双向搜索通常有两种方法:

1. 两个方向交替扩展

2. 选择结点个数较少的那个力向先扩展.方法2克服了两方向结点的生成速度不平衡的状态,明显提高了效率。

算法说明:

设置两个队列c:array[0..1,1..maxn] of jid,分别表示正向和逆向的扩展队列。

设置两个头指针head:array[0..1] of integer 分别表示正向和逆向当前将扩展结点的头指针。

设置两个尾指针tail:array[0..1] of integer 分别表示正向和逆向的尾指针。

maxn表示队列最大长度。

双向宽搜的应用:

{

题目来源:NOIP2002提高组试题

描述 Description

已知有两个字串 A$, B$ 及一组字串变换的规则(至多6个规则):

A1$ -> B1$

A2$ -> B2$

规则的含义为:在 A$中的子串 A1$ 可以变换为 B1$、A2$ 可以变换为 B2$ …。

例如:A$='abcd' B$='xyz'

变换规则为:

‘abc’->‘xu’ ‘ud’->‘y’ ‘y’->‘yz’

则此时,A$ 可以经过一系列的变换变为 B$,其变换的过程为:

‘abcd’->‘xud’->‘xy’->‘xyz’

共进行了三次变换,使得 A$ 变换为B$。

输入格式 Input Format

A$ B$

A1$ B1$ \\

A2$ B2$ |-> 变换规则

... ... /

所有字符串长度的上限为 20。

输出格式 Output Format

若在 10 步(包含 10步)以内能将 A$ 变换为 B$ ,则输出最少的变换步数;

否则输出"NO ANSWER!"

样例输入:

abcd xyz

abc xu

ud y

y yz

样例输出:

3

题目类型:双向广搜

分析:很经典的搜索,双向进行,一种从初始状态向目标状态搜索,另一种从目标状态向初始状态搜索,哪一种的该层节点少就从哪一层向上 或向下搜索,直到两种搜索相交,0ms暴爽,详细解释看下面

}

program NOIP2002p2;

type pp=record

d:longint;

s:string;

end;

var head,tail:array[1..2] of longint;

q:array[1..1000,1..2] of pp;

st:string;

a:array[1..10,1..2] of string;

i,j,tot,k:longint;

//init--------------------------

procedure init;//a[tot,1]记录第tot-1个变换规则的A$字串,a[tot,2]记录第tot-1个变换规则的B$字串,因为第一个是起始串和终止串

var x:longint;

s:string;

begin

tot:=0;

while not eof do

begin

inc(tot);

readln(s);

x:=pos(' ',s);

a[tot,1]:=copy(s,1,x-1);

a[tot,2]:=copy(s,x+1,length(s)-x);

end;

end;

//prepare-----------------------

procedure prepare;//准备工作:第一个队列的头指针指向第一个A$串,第二个队列的头指针指向第一个B$串,存储变换次数的记录均赋值为0

var i,j,k:longint;

begin

head[1]:=1; tail[1]:=1;

head[2]:=1; tail[2]:=1;

q[head[1],1].s:=a[1,1]; q[head[1],1].d:=0;

q[head[2],2].s:=a[1,2]; q[head[2],2].d:=0;

end;

//check-------------------------

procedure check(s1:string; t:longint);

var i:longint;

f:boolean;

begin

f:=false;

for i:=1 to tail[t]-1 do if q[i,t].s=s1 then f:=true;//检验前面的队列中是否出现过相同的字符串

if f=true then dec(tail[t])//出现过,删除掉扩展的节点

else//没出现过的话,向另一个队列中寻找是否有重合,有,即找到了目标,对头成功,大功告成^-^,结束程序即可;没有,接着搜呗!

begin

for i:=1 to tail[3-t] do

if q[i,3-t].s=s1 then

begin

writeln(q[tail[t],t].d+q[i,3-t].d);

close(input); close(output);

halt;

end;

end;

end;

//wide--------------------------

procedure wide(x:longint);

var s1:string;

i,j,t:longint;

begin

for i:=2 to tot do//从第二个变换规则开始枚举A$或B$串

begin

t:=pos(a[i,x],q[head[x],x].s);//从父亲节点的字符串中寻找可以变换的位置

if t<>0 then//找到后扩展节点

begin

repeat

inc(tail[x]);

q[tail[x],x].s:=q[head[x],x].s;

delete(q[tail[x],x].s,t,length(a[i,x]));//删除掉需要更换的字符串

insert(a[i,3-x],q[tail[x],x].s,t);//插入变换后的字符串,当前串即为更新后的字符串

q[tail[x],x].d:=q[head[x],x].d+1;//变换次数加一

check(q[tail[x],x].s,x);//检验是否出现过相同的状态

t:=t+pos(a[i,x],copy(q[head[x],x].s,t+1,length(q[head[x],x].s)-t)); {一个字符串中可能有多个可交s换串}

until pos(a[i,x],copy(q[head[x],x].s,t+1,length(q[head[x],x].s)-t))=0

end;

end;

inc(head[x]);

end;

//work--------------------------

procedure work;

begin

repeat

if (head[1]<=tail[1])and(q[tail[1],1].d<=10)and(tail[1]<=tail[2]) then wide(1);

if (head[2]<=tail[2])and(q[tail[2],2].d<=10)and(tail[1]>tail[2]) then wide(2);//尽量做到两个队列在数量上保持一致

until (head[1]>tail[1]) or (head[2]>tail[2]) or (q[tail[1],1].d+q[tail[2],2].d>10);//中止条件

end;

//main--------------------------

begin

init;

prepare;

work;

writeln('NO ANSWER!');

end.

随便看

 

百科全书收录4421916条中文百科知识,基本涵盖了大多数领域的百科知识,是一部内容开放、自由的电子版百科全书。

 

Copyright © 2004-2023 Cnenc.net All Rights Reserved
更新时间:2025/2/27 11:02:40