• 用erlang求解经典数学问题(1)农夫过河问题


    【题目】

        一位农夫带着一只狼,一只羊和一些菜过河。河边只有一条船,由于船太小,只能装下农夫和他的一样东西。在无人看管的情况下,狼要吃羊,羊要吃菜,请问农夫如何才能用最快的方法将这三样东西平安过河。

    【问题分析】

    总论:

        农夫、狼、羊、菜可以用一个四元组来表示,他们要么在河这边,要么在河那边,只有两种状态,所以最适合用布尔代数来进行分析。

    步骤1:分析题目中的输入、输出

        我们用2#xxxx这4个比特位数字来表示四元组,从高到低位分别表示农夫(b3)、狼(b2)、羊(b1)、菜(b0),每个bit位可为0或1,由此得到2#0000、
    2#0001……2#1110、2#1111这16种状态,0表示这河这边,1表示在河对岸,因此初始状态为2#0000,即所有物体都在河这边,终止状态为2#1111,即所
    有物体都到了河对岸。

    步骤2:分析题干中的约束条件

        约束条件1:“船太小,只能装下农夫和他的一样东西”,意味着狼、羊、菜每次最多只能有一个物体的状态发生变化,即从状态2#x101切换到状态
    2#x100是合法的(只有菜的状态发生了变化),而从状态2#x101切换到状态2#x000是非法的(狼和菜的状态都发生了变化)
        约束条件2:“在无人看管的情况下,狼要吃羊,羊要吃菜”,意味着b2与b1不能同为0或1,b1与b0也不能同为0或1,除非它们与b3的符号一致,例如
    状态2#0110是非法的(狼与羊在同一侧),而状态2#1110是合法的(农夫、狼与羊都在同一侧)。
        约束条件3:这是一个隐含的约束条件,农夫的状态必须在连续的切换,即状态2#0010到状态2#1010是合法的,到状态2#0011是非法的。

    步骤3:分析合法状态

        根据约束条件2,我们分析得出有10种合法状态,可分为两组,分别代表在河这边和在河对岸,用字母表示如下
        Start=2#0000 A=2#0001 B=2#0010 C=2#0100 D=2#0101
                               E=2#1010 F=2#1011 G=2#1101 H=2#1110 End=2#1111

    步骤4:分析状态切换

        根据约束条件1和约束条件3,我们可以分析得到每一个状态的下一个合法状态的集合,如下所示
        Start->E  A->F|G  B->E|F|H  C->G|H     D->G|End  
                        E->B     F->A|B     G->A|C|D  H->B|C     End->D

    步骤5:分析状态图

        根据上面的状态切换,我们可以绘制从Start到End的状态图
        Start--E--B--F--A--G--END
                    |                   |
                   H--------------C
        从图中可得知,从状态Start到状态End有两条可达路径,Start-E-B-H-C-G-END为最短路径

    结论:

        问题最终转化为从起始状态到最终状态是否存在连通图,如果存在,求最短路径

    【解决方案】

        设计了两个进程,分别为主进程和计算进程,主进程派生计算进程,接收计算进程返回的可达路径消息并打印出来,计算进程用于计算可达路径。
        主进程的代码如下所示:

     1 -module(farmercrossriver).
     2 -export([start/0, calu_route/0]).
     3 
     4 %% 4位二进制数比特位的顺序:农夫、狼、羊、菜,0:左岸,1:右岸
     5 
     6 -define(Start, 2#0000).    %起点
     7 -define(End,   2#1111).    %终点
     8 -define(A,     2#0001).    %可达的节点
     9 -define(B,     2#0010).
    10 -define(C,     2#0100).
    11 -define(D,     2#0101).
    12 -define(E,     2#1010).
    13 -define(F,     2#1011).
    14 -define(G,     2#1101).
    15 -define(H,     2#1110).
    16 -define(AllNodes, [?Start, ?End, ?A, ?B, ?C, ?D, ?E, ?F, ?G, ?H]).
    17 
    18 %% 启动
    19 start() ->
    20     register(?MODULE, self()),
    21     spawn(farmercrossriver, calu_route, []),  %派生计算进程
    22     recv_answer([]).
    23     
    24 %% 接收计算出的结果
    25 recv_answer(AllAvailRoutes) ->
    26     receive
    27         {ok, AvailRoute} ->     %计算出一条可达路径
    28             recv_answer([AvailRoute] ++ AllAvailRoutes);
    29         stop ->                 %全部计算完毕
    30             io:format("avail ~w routes~n", [length(AllAvailRoutes)]),
    31             io:format("routes:~w~n", [AllAvailRoutes])
    32     end.


        计算进程的代码如下所示:

     1 %% 计算可达的路径
     2 calu_route() ->
     3     calu_route([], ?Start),
     4     ?MODULE ! stop.     %结束计算
     5     
     6 %% PassedNodes:已经走过的节点
     7 %% NextNode:下一个可达的节点
     8 calu_route(PassedNodes, ?End) ->    %到达终点
     9     ?MODULE ! {ok, lists:reverse([?End] ++ PassedNodes)};    %向主进程发送可达路径
    10 calu_route(PassedNodes, NextNode) ->
    11     IsMember = lists:member(NextNode, PassedNodes),
    12     if
    13         IsMember =:= false ->   %%没有构成回路
    14             NeighborNodes = calu_neighbor_nodes(NextNode, [], ?AllNodes),    %计算当前节点的邻接节点
    15             lists:foreach(fun(Node) -> calu_route([NextNode] ++ PassedNodes, Node) end, NeighborNodes);
    16         true ->
    17             stop
    18     end.
    19     
    20 %% 计算邻接节点
    21 calu_neighbor_nodes(_, NeighborNodes, []) ->
    22     NeighborNodes;
    23 calu_neighbor_nodes(Node, NeighborNodes, WaitCaluNodes) ->
    24     [NewNode | OtherNodes] = WaitCaluNodes,
    25     Value = Node bxor NewNode,   %比特位的异或运算,用来计算有几个物体的位置发生的变更
    26     <<F:1, W:1, S:1, V:1>> = <<Value:4>>, %提取各个物体位置变更的情况
    27     if 
    28         (F=:= 1) and (W+S+V =< 1) ->   %农夫的位置必须发生变更,且其它物体每次最多一个能发生位置变更
    29             calu_neighbor_nodes(Node, [NewNode] ++ NeighborNodes, OtherNodes);
    30         true ->
    31             calu_neighbor_nodes(Node, NeighborNodes, OtherNodes)
    32     end.
    上善若水
  • 相关阅读:
    C++指针
    C++ 结构体和枚举
    提供openssl -aes-256-cbc兼容加密/解密的简单python函数
    最新安全学习视频
    C++复合类型(结构体)
    C艹复合类型(字符串)
    C++复合类型(数组)
    python 搜索引擎Whoosh中文文档和代码 以及jieba的使用
    JSP基础之 C标签中的 varStatues属性
    JSP进阶 之 SimpleTagSupport 开发自定义标签
  • 原文地址:https://www.cnblogs.com/netbuddy/p/2794972.html
Copyright © 2020-2023  润新知