传教士与野人渡河的问题是人工智能类书中经常遇到的问题。书上的例子一般是3个传教士与3个野人,船上最多载2人。不过教我们这门课的老师布置作业让我们画出5个传教士与5个野人渡河,船上最多载3人。我以为很容易画出来的,结果越画越乱。最后决定使用C++写个程序,将搜索的过程表示出来。注:代码是在VS2017环境下编译运行的。
首先,设计三个表,在c++中我使用map 和vector 代替。分别是搜索表,用于存储当前搜索过的所有的状态;Open表,用于存储可被扩展的状态;Close表,用于存储被扩展的过的状态。搜索启发式是 f(n) = 传教士人数+野人人数-2*B+depth。其中船在左岸时B=1,否则B=0。depth表示当前状态在搜索图中的深度。为了能够看清当前搜索状态的信息,我定义了一个结构体:
typedef struct {
int mission; //左岸传教士人数
int canver; //左岸野人人数
bool bank; //true 船在左岸
int depth; //当前搜索的深度
int id; //唯一标识号
int cost; //当前的f(n) = M + C-2*B + depth
}Status;
其中存储的人数均为左岸的人数,id是状态的唯一标识,我定义了一个全局变量,当产生一个新的状态后,便自增1。三个表的定义如下:
map<int, Status> Finding; //保存当前正在搜索中的状态, <id号,status 结构体>
map<int, int> Open; //<id号, cost>
vector<int> Close; //close 表,保存id号
处理的函数包括:
判断当前状态是否合法,即两岸的野人数不可以多于传道士,但是可以有5个野人0个传教士等情况;
判断当前状态是否与已探索状态重复,通过比较左岸人数、船停靠的河岸是否相同判断;
判断当前是否为结果状态;
遍历Finding以及Open;
具体代码如下(注:当控制台显示过多内容的时候,最前