Serie de algoritmos catorce: lobos, ovejas, hortalizas y agricultores cruzando el río

Descripción del título: El granjero necesita transportar lobos, ovejas, verduras y él mismo al otro lado del río. Solo el granjero puede remar en el bote, y el bote es relativamente pequeño. Además del granjero, solo se puede transportar una cosa a la vez. Hay un problema espinoso, es decir, si Sin que el granjero mire, las ovejas robarán verduras y los lobos se comerán ovejas. Por favor, considere una forma para que el agricultor disponga estas cosas de manera segura para cruzar el río con él.

 

        Este tema examina las operaciones lógicas rápidas y la memoria a corto plazo de las personas. Analizar, en la cadena alimenticia del lobo-"oveja" cai, "oveja" está en una posición clave, y la ideología rectora para resolver el problema es siempre aislar "oveja" de "lobo" y "cai", es decir La "oveja" debería ser siempre la última en cruzar el río. Mira una respuesta:

 

El granjero cruza el río con las ovejas

El granjero regresa

El granjero llevó al lobo al otro lado del río.

El granjero vuelve con la oveja

El granjero trae verduras al otro lado del río.

El granjero regresa

El granjero cruza el río con las ovejas

< fin >

 

Mira otra respuesta:

El granjero cruza el río con las ovejas

El granjero regresa

El granjero trae verduras al otro lado del río.

El granjero vuelve con la oveja

El granjero llevó al lobo al otro lado del río.

El granjero regresa

El granjero cruza el río con las ovejas

< fin >

 

La resolución de problemas gira en torno a las ovejas.

         Se han mencionado dos respuestas anteriormente, entonces, ¿cuántas respuestas hay en esta pregunta? La respuesta debe ser exhaustiva con una computadora. La clave para usar una computadora para resolver este problema es el cruce de estado, que es el mismo que el cruce de estado mencionado en el artículo "Algoritmo serie: problema de intercambio de agua de tres cubos". Los granjeros, los lobos, las ovejas y las verduras pueden tener muchos estados según su relación posicional, pero el número total de estados sigue siendo limitado. Nuestro algoritmo atraviesa estos estados finitos hasta que encuentra una transición del estado inicial al estado final De acuerdo con los requisitos del tema, cada estado en este "camino" debe ser un estado legal.

         Ya sea que se trate de un modelo de estado o un algoritmo de transición de estado, esta pregunta es más simple que "dividir 8 litros de agua por igual en tres cubos ". El primero es el estado. El agricultor, el lobo, la oveja y la verdura son cuatro elementos independientes . Su estado es muy simple, ya sea cruzando el río o no cruzando el río. Sólo hay un estado para cada elemento en cualquier momento . Si usa " AQUÍ " para indicar que no ha cruzado el río, use " ALLÍ " para indicar que ha cruzado el río, y use el [ granjero, lobo, oveja, plato ] cuádruple para indicar el estado en un momento determinado, entonces el espacio de estado de esta pregunta es [AQUÍ , AQUÍ , AQUÍ , AQUÍ] es la raíz de un árbol de estado, cuando un nodo hoja del árbol de estado es estado [ALLÍ , ALLÍ , ALLÍ , ALLÍ] , significa que la secuencia de estado desde la raíz hasta el nodo hoja es el problema Una solución.

El algoritmo de transición de estado para esta pregunta sigue siendo una búsqueda en profundidad de todos los estados en el espacio de estados. Dado que los lobos, las ovejas y las verduras no pueden remar en un bote, el algoritmo de transición de estados también es muy simple. No es necesario el problema de " dividir 8 litros de agua en tres cubos ". En ese caso, el método de conversión (acción de vertido) debe determinarse por permutación y combinación. Solo hay 8 operaciones de conversión de estado fijo (acciones de cruce de ríos) en esta pregunta , que son:

El granjero cruza el río solo;

El granjero llevó al lobo al otro lado del río;

El granjero lleva a las ovejas al otro lado del río;

El granjero trajo verduras al otro lado del río;

El granjero regresa solo;

农夫带狼返回;

农夫带羊返回;

农夫带菜返回;

 

        本题的广度搜索边界就是这8个动作,依次对这8个动作进行遍历最多可以转换为8个新状态,每个新状态又最多可以转化为8个新新状态,就形成了每个状态节点有8个(最多8个)子节点的状态树(八叉树)。本题算法的核心就是对这个状态树进行深度优先遍历,当某个状态满足结束状态时就输出一组结果。

 

        需要注意的是,并不是每个动作都可以得到一个新状态,比如“农夫带狼过河”这个动作,对于那些狼已经在河对岸的状态就是无效的,无法得到新状态,因此这个八叉树并不是满树。除此之外,题目要求的合法性判断也可以砍掉很多无效的状态。最后一点需要注意的是,即使是有效的状态,也会有重复,在一次深度遍历的过程中如果出现重复的状态可能会导致无穷死循环,因此要对重复出现的状态进行“剪枝”。

 

        程序实现首先要描述状态模型,本算法的状态定义为:

33 struct ItemState

34 {

35   ......

43   State  farmer,wolf,sheep,vegetable;

44   Action curAction;

35   ......

45 };

算法在穷举的过程中需要保存当前搜索路径上的所有合法状态,考虑到是深度优先算法,用Stack是最佳选择,但是Stack没有提供线性遍历的接口,在输出结果和判断是否有重复状态时都需要线性遍历保存的状态路径,所以本算法不用Stack,而是用Deque(双端队列)。

 

        整个算法的核心就是ProcessState()函数,ProcessState()函数通过对自身的递归调用实现对状态树的遍历,代码如下:

  291 void ProcessState(deque<ItemState>& states)

  292 {

  293     ItemState current = states.back(); /*每次都从当前状态开始*/

  294     if(current.IsFinalState())

  295     {

  296         PrintResult(states);

  297         return;

  298     }

  299 

  300     ItemState next;

  301     for(int i = 0; i < action_count; ++i)

  302     {

  303         if(actMap[i].processFunc(current, next))

  304         {

  305             if(IsCurrentStateValid(next) && !IsProcessedState(states, next))

  306             {

  307               states.push_back(next);

  308               ProcessState(states);

  309               states.pop_back();

  310             }

  311         }

  312     }

  313 }

参数states是当前搜索的状态路径上的所有状态列表,所以ProcessState()函数首先判断这个状态列表的最后一个状态是不是最终状态,如果是则说明这个搜索路径可以得到一个解,于是调用PrintResult()函数打印结果,随后的return表示终止设个搜索路径上的搜索。如果还没有达到最终状态,则依次从8个固定的过河动作得到新的状态,并从新的状态继续搜索。为了避免长长的switch…case语句,程序算法使用了表驱动的方法,将8个固定过河动作的处理函数放在一张映射表中,用简单的查表代替switch…case语句。映射表内容如下:

  279 ActionProcess actMap[action_count] =

  280 {

  281     { FARMER_GO,                  ProcessFarmerGo                },

  282     { FARMER_GO_TAKE_WOLF,        ProcessFarmerGoTakeWolf        },

  283     { FARMER_GO_TAKE_SHEEP,       ProcessFarmerGoTakeSheep       },

  284     { FARMER_GO_TAKE_VEGETABLE,   ProcessFarmerGoTakeVegetable   },

  285     { FARMER_BACK,                ProcessFarmerBack              },

  286     { FARMER_BACK_TAKE_WOLF,      ProcessFarmerBackTakeWolf      },

  287     { FARMER_BACK_TAKE_SHEEP,     ProcessFarmerBackTakeSheep     },

  288     { FARMER_BACK_TAKE_VEGETABLE, ProcessFarmerBackTakeVegetable }

  289 };

 表中的处理函数非常简单,就是根据当前状态以及过河动作,得到一个新状态,如果过河动作与当前状态矛盾,则返回失败,以FARMER_GO_TAKE_WOLF动作对应的处理函数ProcessFarmerGoTakeWolf()为例,看看ProcessFarmerGoTakeWolf()函数的代码:

  182 bool ProcessFarmerGoTakeWolf(const ItemState& current, ItemState& next)

  183 {

  184     if((current.farmer != HERE) || (current.wolf != HERE))

  185         return false;

  186 

  187     next = current;

  188 

  189     next.farmer    = THERE;

  190     next.wolf      = THERE;

  191     next.curAction = FARMER_GO_TAKE_WOLF;

  192 

  193     return true;

  194 }

        当过河动作对应的处理函数返回成功,表示可以得到一个不矛盾的新状态时,就要对新状态进行合法性检查,首先是检查是否满足题目要求,比如狼和羊不能独处以及羊和菜不能独处,等等,这个检查在IsCurrentStateValid()函数中完成。接着是检查新状态是否和状态路径上已经处理过的状态有重复,这个检查由IsProcessedState()函数完成,IsProcessedState()函数的实现也很简单,就是遍历states,与新状态比较是否有相同状态,代码如下:

  131 bool IsProcessedState(deque<ItemState>& states, ItemState& newState)

  132 {

  133     deque<ItemState>::iterator it = find_if( states.begin(), states.end(),

  134                                              bind2nd(ptr_fun(IsSameItemState), newState) );

  135 

  136     return (it != states.end());

  137 }

        运行程序,最终得到的结果是:

 

Find Result 1:

Unknown action, item states is : 0 0 0 0

Farmer take sheep go over river, item states is : 1 0 1 0

Farmer go back, item states is : 0 0 1 0

Farmer take wolf go over river, item states is : 1 1 1 0

Farmer take sheep go back, item states is : 0 1 0 0

Farmer take vegetable go over river, item states is : 1 1 0 1

Farmer go back, item states is : 0 1 0 1

Farmer take sheep go over river, item states is : 1 1 1 1

 

 

Find Result 2:

Unknown action, item states is : 0 0 0 0

Farmer take sheep go over river, item states is : 1 0 1 0

Farmer go back, item states is : 0 0 1 0

Farmer take vegetable go over river, item states is : 1 0 1 1

Farmer take sheep go back, item states is : 0 0 0 1

Farmer take wolf go over river, item states is : 1 1 0 1

Farmer go back, item states is : 0 1 0 1

Farmer take sheep go over river, item states is : 1 1 1 1

 

看来确实是只有两种结果。

 

Supongo que te gusta

Origin blog.csdn.net/orbit/article/details/7563220
Recomendado
Clasificación