【问题标题】:Using Search Algorithm in Python to solve the 3 Wolves and 3 Lambs puzzle使用 Python 中的搜索算法解决 3 Wolves 和 3 Lambs 难题
【发布时间】:2016-03-27 13:20:07
【问题描述】:

这个问题我想了很久,还是不知道怎么解决。

问题如下:

我们有 3 只羔羊和 3 只狼在一边,我们必须让它们过河到另一边。一开始看起来很容易,直到我在这些困难的情况下停下来:

  • 狼不能超过羔羊,这意味着羔羊可以大于或等于狼。
  • 把动物运到对岸的船,最多只能载2个
  • 船必须始终载有动物,这意味着您不能移动空船。

问题必须通过搜索算法来解决,例如 A* 或 BFS 等。

我们都知道,在您提供图形作为输入之前,这些算法无法工作,这就是问题所在。

我们如何从 3 只羔羊和 3 只狼创建一个图形?

我想了很多次,我想到的唯一方法就是尽一切可能。对我来说听起来不错,但仍然没有给我任何进展,因为问题仍然相同,如何实现它或将其编写为 Python 代码以将此图传递给算法以便算法可以解决它?

【问题讨论】:

  • A* 和 BFS 都不需要预先计算整个图
  • 不要将状态(在每个节点上)视为只是羔羊和狼,而是将船添加到状态向量中。有效的过渡会移动船并增加或减少动物数量。
  • @IanMercer 我没听懂,你能详细说明一些代码和示例吗?
  • 图形方法:节点是 (L1,L2,L3,W1,W2,W3,B),L 是羔羊所在的一侧,w 是狼所在的一侧,B 是船的一侧。您的路径应该是从 (0,0,0,1,1,1,0) 到 (1,1,1,0,0,0,0) 或 (1,1,1,0,0,0) ,1)。边缘是关于上述限制的每个节点的每个有效转换。有了这个,您可以使用 BFS 轻松设计算法。这就是您将获得的所有帮助;)
  • @TerryStorm 对不起,你让我更困惑了 >_

标签: python algorithm a-star breadth-first-search


【解决方案1】:

假设每个节点上都有一个状态,表示左岸有多少羔羊和狼,以及船是否在该岸上('0' 表示左,'1' 表示右)。

初始节点为:

Node 0 : { lambs:3, wolves:3, boat:0 }

从这里您可以前往任何满足要求的节点。所以新节点必须有{boat:1}(它去了另一边),它必须带1或2只羔羊和1或2只狼。

下一个可能的节点是:

Node 1 : { lambs:2, wolves:3, boat:1 }  // boat took one lamb
Node 2 : { lambs:1, wolves:3, boat:1 }  // boat took two lambs
Node 3 : { lambs:2, wolves:2, boat:1 }  // boat took one lamb and one wolf
Node 4 : { lambs:3, wolves:1, boat:1 }  // boat took two wolves
Node 5 : { lambs:3, wolves:2, boat:1 }  // boat took one wolf

等等。您可以在探索可能的移动树时动态生成这些。 而且,正如 Erick 在 cmets 中指出的那样,根据规则,其中一些是不合法的,不应该出现在图表中。我会留给你去弄清楚。

结束节点是:

Node N : { lambs:0, wolves:0, boat:1 }

关键的一点是,您需要一个可能状态之间的图表,而不是河流两岸或动物之间的图表。每个州都需要捕捉“世界”模型中的所有内容。

在伪 C# 代码中:

public class Node
{
     public int LambsOnLeft {get; set;}
     public int WolvesOnLeft {get; set;}
     public int Boat {get; set;}

     public IEnumerable<Node> NextStates()
     {
         if (Boat == 0)    // on left
         {
              // boat takes  one lamb from left to right
            if (LamsOnLeft > 0 && LambsOnLeft-1 >= WolvesOnLeft)     
              yield return new Node(LambsOnLeft-1, WolvesOnLeft, 1);
            }
            if (LambsOnLeft > 1 && LambsOnLeft-2 >= WolvesOnLeft)
              yield return new Node(LambsOnLeft-2, WolvesOnLeft, 1);
            }
            // take one wolf
            if (WolvesOnLeft > 0)
                yield return new Node(LambsOnLeft, WolvesOnLeft-1, 1);
            // take two wolves
            if (WolvesOnLeft > 1)
               yield return new Node(LambsOnLeft, WolvesOnLeft-1, 1);
            ...
        }
     }
}

【讨论】:

  • “可能的节点”是否应该是合法节点?他们似乎没有。
  • 哎呀,那里宰了几只羔羊;)是的,它们本来是合法的国家。 @ErickG.Hagstrom
  • @IanMercer 但这意味着我必须生成所有可能性来创建我的树或图表。如何全部生成?我的意思是,你不能简单地用 3 个循环来做到这一点:/
  • 你不需要提前全部生成,你可以根据需要生成它们。从任何状态,您都可以计算出您可以达到的所有新状态(正如我在第一步中展示的那样)。当你得到一个新的状态时,如果你已经访问过那个状态(HashSet,Hashmap)你就不需要再访问它了。
  • @Kale,我添加了一些示例代码,展示了如何延迟生成图表。然后,您只需 BFS 使用 HashSet/HashMap 进行搜索,以避免在搜索解决方案时多次访问同一节点。
猜你喜欢
  • 2015-12-04
  • 1970-01-01
  • 2015-02-05
  • 1970-01-01
  • 2012-05-10
  • 2015-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多