(转载)野人过河算法

经典解法  http://blog.sina.com.cn/s/blog_6f24ba210100v9ev.html

其他参考 :http://blog.sina.com.cn/s/blog_8acf1be10101apex.html

                    http://blog.csdn.net/rongyongfeikai2/article/details/8069015

为防止博主删文,贴原文如下


野人过河问题算法分析


 
     野人过河问题属于人工智能学科中的一个经典问题,问题描述如下:有三个牧师(也有的翻译为传教士)和三个野人过河,只有一条能装下两个人的船,在河的任何一方或者船上,如果野人的人数大于牧师的人数,那么牧师就会有危险. 你能不能找出一种安全的渡河方法呢?
一、算法分析
      先来看看问题的初始状态和目标状态,假设和分为甲岸和乙岸:
         初始状态:甲岸,3野人,3牧师;
                        乙岸,0野人,0牧师;
                         船停在甲岸,船上有0个人;
         目标状态:甲岸,0野人,0牧师;
                          乙岸,3野人,3牧师;
                         船停在乙岸,船上有0个人;
      整个问题就抽象成了怎样从初始状态经中间的一系列状态达到目标状态。问题状态的改变是通过划船渡河来引发的,所以合理的渡河操作就成了通常所说的算符,根据题目要求,可以得出以下5个算符(按照渡船方向的不同,也可以理解为10个算符):
          渡1野人、渡1牧师、渡1野人1牧师、渡2野人、渡2牧师
      算符知道以后,剩下的核心问题就是搜索方法了,本文采用深度优先搜索,通过一个FindNext(…)函数找出下一步可以进行的渡河操作中的最优操作,如果没有找到则返回其父节点,看看是否有其它兄弟节点可以扩展,然后用Process(…)函数递规调用FindNext(…),一级一级的向后扩展。
       搜索中采用的一些规则如下:
   1、渡船优先规则:甲岸一次运走的人越多越好(即甲岸运多人优先),同时野人优先运走;
                                乙岸一次运走的人越少越好(即乙岸运少人优先),同时牧师优先运走;
   2、不能重复上次渡船操作(通过链表中前一操作比较),避免进入死循环;
   3、任何时候河两边的野人和牧师数均分别大于等于0且小于等于3;
   4、由于只是找出最优解,所以当找到某一算符(当前最优先的)满足操作条件后,不再搜索其兄弟节点,而是直接载入链表。
   5、若扩展某节点a的时候,没有找到合适的子节点,则从链表中返回节点a的父节点b,从上次已经选择了的算符之后的算符中找最优先的算符继续扩展b。


二、基本数据结构
      仔细阅读问题,可以发现有些基本东西我们必须把握,例如:每时刻河两岸野人牧师各自的数目、船的状态、整个问题状态。所以我们定义如下几个数据结构:
typedef struct _riverside   //岸边状态类型       
{
      intwildMan;       // 野人数
      intchurchMan;    //牧师数
}RIVERSIDE;
typedef struct _boat   //船的状态类型
      {
  

你可能感兴趣的:(algorithm)