深度宽度优先搜索八数码Word文档格式.docx
《深度宽度优先搜索八数码Word文档格式.docx》由会员分享,可在线阅读,更多相关《深度宽度优先搜索八数码Word文档格式.docx(18页珍藏版)》请在冰豆网上搜索。
(b)=0;
for(iii=0;
iii <
NUM;
iii++) (b)=((b)<<
4)+ a[iii];
}*///将数组a转换为一个64位的整数b
#define RTRANS(a,b)\
{\
long iii;
\
UINT64 ttt=(a);
\
for(iii=NUM -1;
iii>
= 0;
iii--) \
{\
b[iii]=ttt&0xf;
\
ttt>
>=4;
}\
}//将一个64位整数a转换为数组b
//
typedefstructEP_NODE_Tag
{UINT64v;
//保存状态,每个数字占4个二进制位,可解决16数码问题
structEP_NODE_Tag*prev;
//父节点
structEP_NODE_Tag*small, *big;
}EP_NODE;
EP_NODEm_ar[MAX_NODE];
EP_NODE*m_root;
longm_depth;
//搜索深度
EP_NODE m_out[MAX_DEP];
//输出路径
longmove_gen(EP_NODE *node,EP_MOVE *move)
{long pz;
//0的位置
UINT64t=0xf;
for(pz=NUM - 1;
pz>=0;
pz--)
{if((node->
v&
t)==0)
{ break;
//找到0的位置
}
t<<
=4;
}
switch(pz)
{case0:
move[0].x=0;
move[0].y=1;
move[1].x=0;
move[1].y=3;
return2;
case1:
move[0].x=1;
move[0].y=0;
move[1].x=1;
move[1].y=2;
move[2].x=1;
move[2].y=4;
return3;
case2:
move[0].x=2;
move[0].y=1;
move[1].x=2;
move[1].y=5;
return 2;
case 3:
move[0].x=3;
move[0].y=0;
move[1].x=3;
move[1].y=6;
move[2].x=3;
move[2].y=4;
return3;
case 4:
move[0].x=4;
move[0].y=1;
move[1].x=4;
move[1].y=3;
move[2].x=4;
move[2].y=5;
move[3].x=4;
move[3].y=7;
return4;
case5:
move[0].x=5;
move[0].y=2;
move[1].x=5;
move[1].y=4;
move[2].x=5;
move[2].y=8;
return3;
case6:
move[0].x=6;
move[0].y=3;
move[1].x=6;
move[1].y=7;
return 2;
case7:
move[0].x=7;
move[0].y=6;
move[1].x=7;
move[1].y=4;
move[2].x=7;
move[2].y=8;
case8:
move[0].x=8;
move[0].y=5;
move[1].x=8;
move[1].y=7;
return2;
return0;
long mov(EP_NODE*n1, EP_MOVE*mv,EP_NODE *n2)
//走一步,返回走一步后的结果
charss[NUM];
RTRANS(n1->v,ss);
XCHG(ss[mv->
x],ss[mv->
y]);
TRANS(ss,n2->
v);
return 0;
longadd_node(EP_NODE*node, longr)
{
EP_NODE*p=m_root;
EP_NODE*q;
while(p)
{q=p;
if(p->
v==node->
v) return0;
elseif(node->
v>
p->
v)p=p->
big;
elseif(node->v<
p->
v)p=p->
small;
m_ar[r].v=node->
v;
m_ar[r].prev=node->prev;
m_ar[r].small=NULL;
m_ar[r].big=NULL;
if(node->
v >
q->
v)
{q->
big=&
m_ar[r];
else if(node->
v<
q->v)
{q->
small=&m_ar[r];
return 1;
/*得到节点所在深度*/
longget_node_depth(EP_NODE*node)
{long d=0;
while(node->
prev)
{d++;
node=node->
prev;
returnd;
/*返回值:
成功-返回搜索节点数,节点数不够-(-1),无解-(-2)*/
long bfs_search(char*begin,char*end)
{long h=0,r=1, c,i,j;
EP_NODE l_end,node,*pnode;
EP_MOVE mv[4];
//每个局面最多4种走法
TRANS(begin,m_ar[0].v);
TRANS(end,l_end.v);
m_ar[0].prev=NULL;
m_root=m_ar;
m_root->
small=NULL;
m_root->
big=NULL;
while((h<r) &
&
(r<
MAX_NODE- 4))
{c=move_gen(&
m_ar[h],mv);
for(i=0;
i<
c;
i++)
{mov(&
m_ar[h],&
mv[i],&node);
node.prev= &
m_ar[h];
if(node.v== l_end.v)
{ pnode=&node;
j=0;
while(pnode->
prev)
{m_out[j]=*pnode;
j++;
pnode=pnode->prev;
m_depth=j;
returnr;
if(add_node(&
node,r))r++;
//只能对历史节点中没有的新节点搜索,否则会出现环
h++;
printf("
\rSearch...%9d/%d@ %d"
h,r,get_node_depth(&
m_ar[h]));
if(h==r)
{return-2;
}
else
{return-1;
longcheck_input(char*s,chara, longr)
{ longi;
for(i=0;
i<
r;
i++)
{ if(s[i]== a - 0x30)return0;
return1;
long check_possible(char*begin,char*end)
{char fs;
longf1=0,f2=0;
long i,j;
for(i=0;
i <
NUM;
i++)
{fs=0;
for(j=0;
j<
i;
j++)
if((begin[i]!
=0)&
(begin[j]!
= 0)&
&(begin[j]<
begin[i]))fs++;
f1+=fs;
fs=0;
for(j=0;
j<i;
j++)
{if((end[i] !
=0) &&
(end[j]!
=0) &
(end[j] <
end[i]))fs++;
f2+=fs;
if((f1&
1)== (f2&
1))return1;
return0;
voidoutput(void)
{ longi, j, k;
charss[NUM];
for(i=m_depth-1;
i>
=0;
i--)
{RTRANS(m_out[i].v,ss);
for(j=0;
j<
SIZE;
j++)
{for(k=0;
k<
SIZE;
k++)
{printf("
%2d"
ss[SIZE* j+k]);
printf("
\n"
);
printf("
);
intmain(void)
{ char s1[NUM];
chars2[NUM];
long r;
char a;
printf("请输入开始状态:
"
r=0;
while(r <
NUM)
{ a=getchar();
if(a>=0x30&
&a <
0x39 &
check_input(s1, a,r))
{s1[r++]=a-0x30;
printf("
%c"
a);
printf("\n请输入结束状态:
r=0;
while(r<
NUM)
{a=getchar();
if(a>
=0x30&
a<
0x39&
&check_input(s2,a,r))
{ s2[r++]=a-0x30;
if(check_possible(s1,s2))
{r=bfs_search(s1, s2);
printf("
\n");
if(r>
=0)
{printf("查找深度=%d,所有的方式=%ld\n"
m_depth, r);
output();
elseif(r ==-1)
{printf("
没有找到路径.\n"
elseif(r==-2)
{printf("
这种状态变换没有路径到达.\n"
{printf("不确定的错误.\n"
else
{ printf("
不允许这样移动!
\n");
return0;
方法二:
用MATLAB实现
program8no_bfs;
{八数码的宽度优先搜索算法}
Const
Dir:
array[1..4,1..2]ofinteger{四种移动方向,对应产生式规则}
=((1,0),(-1,0),(0,1),(0,-1));
n=10000;
Type
T8no =array[1..3,1..3]ofinteger;
TList=record
Father :
integer;
{父指针}
dep:
byte;
{深度}
X0,Y0:
byte;
{0的位置}
State:
T8no;
{棋盘状态}
end;
Var
Source,Target:
T8no;
List :
array[0..10000]ofTList;
{综合数据库 }
Closed,open,Best:
integer {Best表示最优移动次数}
Answer:
integer;
{记录解}
Found:
Boolean;
{解标志}
procedure GetInfo;
{读入初始和目标节点}
var i,j:
integer;
begin
for i:
=1 to3do
forj:
=1to3do read(Source[i,j]);
fori:
=1to 3do
forj:
=1 to 3doread(Target[i,j]);
procedure Initialize;
{初始化}
varx,y:
integer;
begin
Found:
=false;
Closed:
=0;
open:
=1;
withList[1] dobegin
State:
=Source;
dep:
=0;
Father:
=0;
Forx:
=1to 3do
For y:
=1to 3do
ifState[x,y]=0then Beginx0:
=x;
y0:
=y;
End;
end;
end;
FunctionSame(A,B :
T8no):
Boolean;
{判断A,B状态是否相等}
Var i,j:
integer;
Begin
Same:
=false;
Fori:
=1to 3doforj:
=1to3do ifA[i,j]<>
B[i,j]thenexit;
Same:
=true;
End;
Functionnot_Appear(new:
tList):
boolean;
{判断new是否在List中出现}
vari:
integer;
begin
not_Appear:
=false;
fori:
=1toopendoifSame(new.State,List[i].State)thenexit;
not_Appear:
=true;
end;
procedureMove(n :
tList;
d:
integer;
varok :
boolean;
varnew:
tList);
{将第d条规则作用于n得到new,OK是new是否可行的标志}
var x,y :
integer;
begin
X :
=n.x0+Dir[d,1];
Y:
=n.y0 +Dir[d,2];
{判断new的可行性}
if not ((X >
0)and ( X <
4 )and(Y>
0)and(Y< 4 ))thenbeginok:
=false;
exit end;
OK:
=true;
new.State:
=n.State;
{new=Expand(n,d)}
new.State[X,Y]:
=0;
new.State[n.x0,n.y0]:
=n.State[X,Y];
new.X0:
=X;
new.Y0:
=Y;
end;
procedureAdd(new:
tList);
{插入节点new}
begin
ifnot_Appear(new)then Begin {如果new没有在List出现}
Inc(open);
{new加入open表}
List[open] :
=new;
end;
end;
procedureExpand(Index:
integer;
varn:
tList);
{扩展n的子节点}
vari :
integer;
new:
tList;
OK:
boolean;
Begin
ifSame(n.State, Target) thenbegin {如果找到解}
Found:
= true;
Best:
=n.Dep;
Answer:
=Index;
Exit;
end;
Fori:
=1 to4dobegin {依次使用4条规则}
Move(n,i,OK,new);
ifnotok thencontinue;
new.Father:
=Index;
new.Dep :
=n.dep+ 1;
Add(new);
end;
procedure GetOutInfo;
{输出}
procedureOutlook(Index:
integer);
{递归输出每一个解}
var i,j:
integer;
begin
ifIndex=0thenexit;
Outlook(List[Index].Father);
withList[Index]do
fori:
=1to3dobegin
forj:
=1to 3dowrite(State[i,j],'
'
writeln;
end;
writeln;
end;
begin
Writeln('
Total =',Best);
Outlook(Answer);
end;
procedureMain;
{搜索主过程}
begin
Repeat
Inc(Closed);
Expand(Closed,List[Closed]);
{扩展Closed}
Until(Closed>=open)orFound;
ifFound thenGetOutInfo {存在解}
else Writeln('noanswer'
{无解}
Begin
Assign(Input,'
input.txt'
ReSet(Input);
Assign(Output,'
Output.txt'
ReWrite(Output);
GetInfo;
Initialize;
Main;
Close(Input);
Close(Output);
End.
五、实验结果
六、实验总结
通过实验问题的求解过程就是搜索的过程,采用适合的搜索算法是关键的,因为对求解过程的效率有很大的影响,包括各种规则、过程和算法等推理技术。
八数码问题中,将牌的移动来描述规则,是一种相对较简单的方法。
用广度优先算法实现八数码问题,其实是一种比较费劲的方式;
然而深度优先将是一个很好的方法,利用深度优先不但减少了程序实现的时间,是一种不错的方式。
但最好的方式是启发式搜索方式实现,在很大程度上相对于前两种方式是一种非常好的实现方式,不但节省了时间,也节省了空间。
通过这次试验使我对搜索算法有了一定的了解,并对实现这个问题的执行过程有了更一步的认识。
也通过它解决了八数码问题,但在实际的过程中还存在很多问题,也看了一些辅助书籍,以后还要加强学习,加强理论与实际的练习。
总之,这次试验使我受益匪浅。