BFS宽搜广度c++Word下载.docx
- 文档编号:16442833
- 上传时间:2022-11-23
- 格式:DOCX
- 页数:45
- 大小:78.99KB
BFS宽搜广度c++Word下载.docx
《BFS宽搜广度c++Word下载.docx》由会员分享,可在线阅读,更多相关《BFS宽搜广度c++Word下载.docx(45页珍藏版)》请在冰豆网上搜索。
=ch(si,sj-1);
ch(si,sj-1):
(4)空格向右移动。
Ifsj+1<
ch(si,sj+1):
用数组DI和HJ来表示移动的行列增量,则有:
R1234
方向左上右下
DI0-101
HJ-1010
搜索策略。
按照问题分析中提出的方法,算法设计如下:
Programnum8;
初始化;
把初始布局存入数据库data;
设首指针closed:
=0;
尾指针open:
=1;
Repeat
Closed增1,取出队列首记录为当前被扩展结点;
Forr:
=1to4do{r是规则编号}
Begin
If新空格位置合法then
Begin
Open增1,并把新布局存入队尾;
If新布局与队列中原有记录重复then删除新产生的布局
Elseif达到目标then输出并退出;
End;
End;
Untilclosed>
=open;
{队列空}
源程序如下;
{$A-,B-,D-,E-,F-,G-,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X-,Y-}
{$M65521,0,655360}
const
fn1='
input.txt'
;
fn2='
output.txt'
type
xtype=array[1..3,1..3]of0..8;
ctype=array[1..10000]of^xtype;
dtype=array[1..10000]ofinteger;
var
a,b:
xtype;
c:
ctype;
dep,father:
^dtype;
x0:
array[1..10000,1..2]ofbyte;
procedureinit;
var
f:
text;
i,j:
integer;
begin
new(dep);
new(father);
fori:
=1to10000donew(c[i]);
assign(f,fn1);
reset(f);
=1to3doforj:
=1to3doread(f,a[i,j]);
=1to3doread(f,b[i,j]);
close(f)
end;
procedurecalc;
i,j,k,l,x:
open,closed:
d:
procedurebool;
{判断当前状态是否到达目标状态}
i,j,k,l:
e:
dtype;
l:
=0;
forj:
=1to3do
fork:
ifb[j,k]<
>
c[closed]^[j,k]then
=1;
ifl=0then
assign(f,fn2);
rewrite(f);
j:
repeat
inc(j);
e[j]:
=closed;
closed:
=father^[closed]
untilclosed=0;
=jdownto1do
write(f,c[e[k]]^[i,j]:
3);
writeln(f)
close(f);
halt
end{输出答案}
procedurecheakup;
{判断是否重复,如果是则删掉当前状态}
=1toclosed-1do
ifc[i]^[j,k]<
dec(closed);
exit
end
bool
open:
c[closed]^:
=a;
dep^[closed]:
father^[closed]:
bool;
ifa[i,j]=0then
x0[1,1]:
=i;
x0[1,2]:
=j
inc(open);
d:
=c[open]^;
i:
=x0[open,1];
=x0[open,2];
k:
=dep^[open];
ifi>
1then{空格向上移动}
inc(closed);
=d;
c[closed]^[i,j]:
=c[closed]^[i-1,j];
c[closed]^[i-1,j]:
=k+1;
=open;
x0[closed,1]:
=i-1;
x0[closed,2]:
=j;
cheakup
ifi<
3then{空格向下移动}
=c[closed]^[i+1,j];
c[closed]^[i+1,j]:
=i+1;
ifj>
1then{空格向左移动}
=c[closed]^[i,j-1];
c[closed]^[i,j-1]:
=j-1;
ifj<
3then{空格向右移动}
=c[closed]^[i,j+1];
c[closed]^[i,j+1]:
=j+1;
until(open>
=closed)or(closed>
=10000);
procedureprint;
{输出无解}
writeln(f,'
Nosolution!
'
);
begin
init;
calc;
end.
运行上面程序的结果为:
283283203023123123
164→104→184→184→084→804
705765765765765765
上述程序产生的搜索图如图所示,其中每个布局旁的数字是产生的顺序号。
从搜索图中可以看出,程序运行中,先产生深度为1的所有结点,然后再产生深度为2的所有结点,……,最后产生含有目标深度为5的结点结束。
先往“横向”扩展,再往纵向深入,因此称为广度优先搜索。
程序运行产生结点过程图
●基本方法
综上所述,广度优先的基本算法如下:
ProgramBFS;
建立数据库data;
初始状态存入数据库data;
设队列首指针closed:
队列尾指针open:
Closed增1,取出closed所指结点进行扩展;
=1tormaxdo{r为产生规则编号}
If子结点符合条件then
Open增1,并把新结点存入数据库队尾;
If新结点与原有结点重复then删去该结点(open减1)
Elseif新结点即目标then输出并退出;
从上例可以看出,广度优先搜索法可以求出步数最少的解,即深度最少的解。
与深度优先搜索类似,不同的问题,用广度优先搜索的基本算法是一样的,但在数据库的表示方法、产生的结点是否符合条件和重复的判断上可以有不同的编程技巧,程序的运行效率也有所不同。
以八数码问题为例,上面的程序中用3*3的二维数组表示布局比较直观,但在判断重复,判断是否达到目标方面,却给程序增加了复杂性,也影响了运行速度。
可以改用字符串形式来表示布局。
例如初始布局表示为“283164705”,目标布局表示为“123804765”。
产生规则也必须作相应改动。
设空格当前位置是SI,则有:
(1)空格向上移动:
空格的位置减3,即交换SI和SI-3的字符;
(2)空格向左移动:
空格的位置减1,即交换SI和SI-1的字符;
(3)空格向右移动:
空格的位置加1,即交换SI和SI+1的字符;
(4)空格向下移动:
空格的位置加3,即交换SI和SI+3的字符。
如设规则编号为k,则上述四条规则可归纳为一条:
交换SI和SI+(2*k-5)的字符
布局用字符串表示,使得判断重复过程和判断目标的过程变得很简单,只需判断两个字符串是否相等就可以了。
按照上述的改进,读者可自己编制的解八数码问题的程序。
【例题】翻币问题。
有N个硬币(N≥6)正面朝上排成一排,每次将5个硬币翻过来放在原位置,直到最后全部硬币翻成反面朝上为止。
编程让计算机找出步数最少的翻法并把翻币过程及次数打印出来(用O表示正面,*表示反面)。
【分析】由于问题要求找出最少步骤,用广度优先搜索法来求解。
表面看,翻币的过程与正反面硬币的排列位置有关,但只要经过仔细分析会发现:
实际上翻币过程仅与硬币正反面的个数有关,与它们的位置是无关的。
例如下面两种状态:
O*O*O*OO和***OOOOO
都只要把5个正面朝上的硬币翻过来就达到了目标。
因此在搜索过程中只需考虑当前状态正面朝上的个数。
又如,如果当前状态是:
***OO***
翻第1,2,4,6,8个得到:
OO**OO*O
而翻第3,5,6,7,8个得到:
**OO*OOO
这两种翻法虽翻的硬币不同,但都是把原状态中4个反面朝上1个正面朝上的硬币翻过来。
结果状态不同,但都有5个硬币正面朝上,再翻一次就都可以达到目标。
所以产生规则也只需考虑翻正面朝上的硬币的个数不同就可以了。
综合数据库中每个记录设计为三项:
当前状态中硬币正面朝上的个数,父结点位置,由父结点翻了几个正面朝上的硬币得到当前状态。
数据库本身用队列形式。
产生规则有六条,即翻R个正面朝上的硬币:
if当前结点正面朝上的硬币个数M≥R且反面朝上的个数≥5-R
then子结点data=(M-R)+(5-R){R=0,1,2,……,5}
采用广度优先搜索法求解。
源程序如下:
{$A-,B-,D-,E-,F-,G-,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X-}
n:
a:
array[1..8000,1..3]ofinteger;
{数据库}
b:
array[0..8000]ofboolean;
{标志数组——判重}
{a[i,1]:
父节点编号}
{a[i,2]:
M_zhengmiancaoshang}
{a[i,3]:
fanlejige}
r,m:
{open、closed为队列的首位指针}
i,j,k,l,h:
array[1..5000]ofinteger;
st:
array[1..5000]ofchar;
write('
step0:
'
=1tondowrite('
o'
writeln;
=1tondost[i]:
='
d[j]:
=a[i,1];
untili=0;
=j-1downto1do
=a[d[i],3];
=5-k;
forh:
=1tondo
ifst[h]='
then
ifk>
0thenbegindec(k);
st[h]:
*'
else
ifl>
0thenbegindec(l);
step'
j-i:
4,'
:
=1tondowrite(st[h]);
writeln
fillchar(b,sizeof(b),true);
b[n]:
=false;
a[1,1]:
a[1,2]:
=n;
a[1,3]:
m:
=a[open,2];
forr:
=0to5do
if(m>
=r)and(n-m>
=5-r)and(b[m-r+5-r])then
b[m-r+5-r]:
a[closed,1]:
a[closed,2]:
=m-r+5-r;
a[closed,3]:
=r;
ifa[closed,2]=0thenprint
untilopen>
writeln('
Noanswer!
Inputn:
readln(n);
ifn<
6thenwriteln('
Inputerror!
)elsecalc
【例题】有两个无刻度标志的水壶,分别可装x升和y升(x、y为整数,x、y<
=100)的水,设另有一水缸,可用来向水壶灌水或倒出水,两水壶间,水也可以相互倾灌。
已知x升壶为满壶,y升壶为空壶。
问如何通过倒水或灌水操作,用最少步数能在y升壶中量出z(<
=100)升的水来。
【分析】本题要求最少步数,显然应采用广度优先搜索。
设A水壶内有a升水,B水壶内有b升水,则最多会有六种产生规则:
(1)当a>
0且b<
y时,可以从水壶A倒MINA水壶B水壶
(a,y-b)升水给水壶B。
这时水壶A内有a-MIN(a,y-b)升水;
水壶B内有b+MIN(a,y-b)升水;
(2)当b>
0且a<
x时,可以从水壶B倒MIN(b,x-a)升水给水壶A。
这时水壶A内有a+MINA水壶B水壶A水壶B水壶
(b,x-a)升水;
水壶B内有b+MIN(b,x-a)升水;
A水壶A水壶
(3)当a>
0时,可以从水壶A倒a升水给水缸4、当a<
x时,可以从水缸倒x-a升水给水壶A这时水壶A内有0升水;
这时水壶A内有x升水,水壶B内有b升水;
水壶B内有b升水;
B水壶B水壶
(4)当b>
0时,可以从水壶B倒b升水给水缸水壶B这时水壶A内有a升水;
水壶B内有0升水;
(5)当b<
y时,可以从水缸倒y-b升水给这时水壶A内有a升水水壶B内有y升水。
初始时,水壶A内有x升水,水壶B内有0升水。
综合数据库:
可用一个记录类型描述一个状态:
atype=record
father,a,b:
word;
end;
father记录当前节点的父亲节点的编号,a、b表示当前状态中,水壶A和水壶B里各有多少水。
整个数据库可用一个以为数组DATA[1..10000]ofatype;
另外用一个标志数组bool,当bool[I,j]为真,表示水壶A为I升,水壶B为j升的状态还没有产生过,反之则表示已产生过。
atype=recordfather,a,b:
word;
btype=array[0..100,0..100]ofboolean;
x,y,z:
data:
array[1..10000]ofatype;
bool:
^btype;
{广搜}
functionmin(a,b:
word):
{求较小值}
ifa<
bthenmin:
=aelsemin:
=b
{输出}
array[1..10000]ofinteger;
repeatj:
=data[i].fatheruntili=0;
setp'
3,'
data[d[i]].a:
5,data[d[i]].b:
5);
readln;
halt{结束}
procedureevaluate(i,j:
word);
{赋值}
bool^[i,j]:
data[closed].a:
data[closed].b:
data[closed].father:
ifj=zthenprint
new(bool);
fillchar(bool^,sizeof(bool^),true);
bool^[x,0]:
data[1].a:
=x;
data[1].b:
data[1].father:
if(z=x)or(z=0)thenprint;
=data[open].a;
=data[open].b;
=min(i,y-j);
=min(x-i,j);
if(i>
0)and(j<
y)and(bool^[i-k,j+k])thenevaluate(i-k,j+k);
if(j>
0)and(i<
x)and(bool^[i+l,j-l])thenevaluate(i+l,j-l);
0)and(bool^[0,j])thenevaluate(0,j);
0)and(bool^[i,0])thenevaluate(i,0);
if(i<
x)and(bool^[x,j])thenevaluate(x,j);
if(j<
y)and(bool^[i,y])thenevaluate(i,y){六种产生规则}
readln{输出无解}
Inputx,y,z:
readln(x,y,z);
calc
【例题】房间问题。
图4-9意示出了一
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- BFS 广度 c+