上一篇文章里讲到了广度优先搜索法,并以8数码问题为例。8数码问题比较简单,一般不超过30步即可求解。搜索的节点也不会超过1000000。而如下这个问题的步数是56,如果直接用广度优先搜索,节点数量会多的难以想象。
#######
#BLACK#
## # ## #是墙
#WHITE#
#######
|
#######
#WHITE#
## # ##
#BLACK#
#######
问题就是将上述两个状态互换。
双向广度优先搜索法我是在“人工智能爱好者”网站上看到的。其思想是同时从开始状态和结束状态开始广度优先搜索,随着搜索的进行,双方会在中间相遇。由此就找到了一个可行解,而且是最少步数解。具体方法是每增加一个节点,就在对方已搜索的节点中查找,如果找到相同状态节点,则为找到解。
以下这个程序和一般的广度优先搜索并无太大区别,区别主要是双向相遇的判断。
/*
-----------
#######
#BLACK#
## # ## #是墙
#WHITE#
#######
|
#######
#WHITE#
## # ##
#BLACK#
#######
-----------
*/
#include <stdio.h>
typedef unsigned long long UINT64;
typedef struct
{
char x; //位置x和位置y上的数字换位
char y; //其中x是0所在的位置
} PZ_MOVE;
typedef struct PZ_NODE_Tag
{
UINT64 v;
struct PZ_NODE_Tag *prev, *small, *big;
} PZ_NODE;
#define ROW 3
#define COL 5
#define NUM (ROW * COL)
#define MAX_NODE 2000000
#define MAX_DEP 100
#define MAX_MOVE 6
#define XCHG(a, b) { a=a + b; b=a - b; a=a - b; }
#define TRANS(a, b) { long iii; (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
//
PZ_NODE m_ar1[MAX_NODE];
long m_depth1; //搜索深度
PZ_NODE m_out1[MAX_DEP]; //输出路径
PZ_NODE *m_root1;
PZ_NODE m_ar2[MAX_NODE];
long m_depth2; //搜索深度
PZ_NODE m_out2[MAX_DEP]; //输出路径
PZ_NODE *m_root2;
//
long move_gen(PZ_NODE *node, PZ_MOVE *mv)
{
long c=0;
char st[NUM];
RTRANS(node->v, st);
if((st[0] != 0) && (st[1] == 0))
{
mv[c].x=1;
mv[c].y=0;
c++;
if(st[2] == 0)
{
mv[c].x=2;
mv[c].y=0;
c++;
}
if(st[6] == 0)
{
mv[c].x=6;
mv[c].y=0;
c++;
}
}
if(st[1])
{
if(st[0] == 0)
{
mv[c].x=0;
mv[c].y=1;
c++;
}
if(st[2] == 0)
{
mv[c].x=2;
mv[c].y=1;
c++;
if(st[3] == 0)
{
mv[c].x=3;
mv[c].y=1;
c++;
}
}
if(st[6] == 0)
{
mv[c].x=6;
mv[c].y=1;
c++;
if(st[11] == 0)
{
mv[c].x=11;
mv[c].y=1;
c++;
}
}
}
if(st[2])
{
if(st[1] == 0)
{
mv[c].x=1;
mv[c].y=2;
c++;
if(st[0] == 0)
{
mv[c].x=0;
mv[c].y=2;
c++;
}
if(st[6] == 0)
{
mv[c].x=6;