【引言】这两天读司守奎《建模算法与应用》读到一个非常有意思的问题,就是小学时我们都玩过的一道奥赛题,狼羊菜渡河问题。

【问题🐺🐏】

某人带狼、羊和蔬菜渡河,一小船除需要人划外,每次只能载一物过河。而当人不在场时,狼会吃羊,羊会吃菜。问此人应如何渡河?

【最开始思路】小学奥赛题是怎么解的来着...,放弃那种想法,还真的想不到,看看答案,觉得好神奇,居然可以跟我们学过的图论相关联。

【思路】

  • 我们用一个四维向量来表示状态,第一个分量表示人,第二个分量表示狼,第三个分量表示羊,第四个分量表示蔬菜。它们的状态如何展示呢,由于整个问题只有两种情况:在此岸和在对岸,因此我们用0、1两种数字来表示,1表示在此案,0表示在对岸。

由题意,我们知人不在场时,狼会吃羊,所以状态(0,1,1,0)是一个不可行的状态。由此,我们可以列举出所有可行状态:(1 1 1 1) (1 1 1 0) (1 1 0 1) (1 0 1 1) (1 0 1 0) (0 1 0 1) (0 1 0 0) (0 0 1 0) (0 0 0 1) (0 0 0 0)总共10种情况。

  • 对于每一次的渡河行为,都是一次状态的改变。我们现在构造赋权图 G(V,E,W),其顶点集合中的顶点分别表示10个可行状态。当且仅当对应的两个可行状态存在可行转移时,两顶点有边相连接,并且边的权重为1,当两个顶点不存在可行转移时,两顶点之间不存在边相连接,我们把其权重设为。

因此,什么是可行转移,根据题目可知,可行转移即为一种可以渡河的状态,我们再引入一个四维状态转移向量,用其反映摆渡状态。用1表示渡河,0表示未渡河。则可能出现的状态转移向量有四种:(1,0,0,0) (1,1,0,0) (1,0,1,0) (1,0,0,1)。

  • 现在,问题变成了在图G中寻找一条由状态(1,1,1,1)出发到状态(0,0,0,0)的最短路径。如何得出邻接矩阵成为难点。我们现在有了状态和状态转移向量,因此我们规定状态向量与状态转移向量之间的运算如下:

       1+1=0;1+0=1;0+1=1;0+0=0;(即异或运算)

如果一个可行状态向量加上一个状态转移向量还属于可行状态,那么这两个可行状态对应的顶点之间有边相连接。

【代码】

%%狼羊菜渡河问题
%%清空
clear;clc;
%%建立模型
a = [1 1 1 1;1 1 1 0;1 1 0 1;1 0 1 1;1 0 1 0;0 1 0 1;0 1 0 0;0 0 1 0;0 0 0 1;0 0 0 0];%所有可以出现的状态,即可行状态
b = [1 0 0 0;1 0 0 1;1 1 0 0;1 0 1 0;];%可能出现的转移状态,即状态转移情况
%%邻接矩阵赋值
w = zeros(10);%邻接矩阵初始化
for i = 1:9
    for j = i+1:10
        for k = 1:4
            if findstr(xor(a(i,:),b(k,:)),a(j,:))
                w(i,j) = 1;
            end
        end
    end
end
%%最短路径算法
w = w';%转化为下三角矩阵
c = sparse(w);%构造为稀疏矩阵
[x,y,z] = graphshortestpath(c,1,10,'directed',0);
disp(x);
disp(y);
%%画图
h = view(biograph(c,[],'ShowArrows','off','ShowWeights','off'));
Edges = getedgesbynodeid(h);
set(Edges,'LineColor',[0 0 0]);
set(Edges,'LineWidth',1.5);

【结果】

状态转移顺序: 1     6     3     7     2     8     5    10

狼羊菜过河问题python 狼羊菜过河问题建模_狼羊菜过河问题python

第一次运羊过河,空船返回;第二次运菜过河,带羊返回;第三次带狼过河,空船返回;第四次带羊过河。OVER!!!❀❀❀