用Python中的搜索算法解决三狼三羊之谜

用Python中的搜索算法解决三狼三羊之谜,python,algorithm,a-star,breadth-first-search,Python,Algorithm,A Star,Breadth First Search,这个问题我想了很久,想不出怎么解决 问题如下: 我们有三只小羊和三只狼在一条河里,我们必须让它们通过河到另一边。一开始看起来很容易,直到我在这些困难的情况下停下来: 狼不能超过羊羔,这意味着羊羔可以超过或等于狼 这艘船把动物运到另一边,最多只能载2只 船必须总是载着动物,这意味着你不能移动空船 这个问题必须通过搜索算法来解决,比如A*或BFS等 我们都知道,这些算法只有在您提供一个图形作为输入时才会起作用,问题就出在这里 我们如何从3只羔羊和3只狼创建一个图 我想了很多次,唯一能想到的办法就

这个问题我想了很久,想不出怎么解决

问题如下:

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

  • 狼不能超过羊羔,这意味着羊羔可以超过或等于狼
  • 这艘船把动物运到另一边,最多只能载2只
  • 船必须总是载着动物,这意味着你不能移动空船
这个问题必须通过搜索算法来解决,比如A*或BFS等

我们都知道,这些算法只有在您提供一个图形作为输入时才会起作用,问题就出在这里

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


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

假设每个节点上都有一个状态,表示左岸有多少羔羊和狼,以及船是否在该岸(“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
等等。您可以在探索可能的移动树时动态生成这些移动。而且,正如埃里克在评论中指出的,根据规则,其中一些是不合法的,不应该出现在图表中。我会让你去弄清楚的

结束节点为:

Node N : { lambs:0, wolves:0, boat:1 }
关键是你需要一个可能状态之间的图表,而不是河流两岸或动物之间的图表。每个州都需要捕捉“世界”模型中的一切

在伪C#代码中:

公共类节点
{
public int LambsOnLeft{get;set;}
public int WolvesOnLeft{get;set;}
公共int船{get;set;}
公共IEnumerable NextStates()
{
如果(船==0)//在左侧
{
//船从左到右抓一只羔羊
if(LamsOnLeft>0&&LambsOnLeft-1>=WolvesOnLeft)
产生返回新节点(LambsOnLeft-1,WolvesOnLeft,1);
}
if(LambsOnLeft>1&&LambsOnLeft-2>=WolvesOnLeft)
产生返回新节点(LambsOnLeft-2,WolvesOnLeft,1);
}
//抓一只狼
如果(WolvesOnLeft>0)
产生返回新节点(LambsOnLeft,WolvesOnLeft-1,1);
//抓两只狼
如果(WolvesOnLeft>1)
产生返回新节点(LambsOnLeft,WolvesOnLeft-1,1);
...
}
}
}

无论是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)或(1,1,1,0,0,1)。根据上述限制,边缘是每个节点的每个有效过渡。有了这一点,您可以使用BFS轻松地设计算法。这就是你将得到的全部帮助;)@恐怖袭击我很抱歉,你让我更困惑了,我很抱歉我难以理解:(这些“可能的节点”应该是合法的节点吗?它们看起来不是。哎呀,在那里杀了几只羔羊;)是的,它们应该是合法的国家@埃里克。Hagstrom@IanMercer但这意味着我必须生成所有的可能性来创建我的树或图形。如何生成它们?我的意思是,你不能简单地用3个循环来实现这一点:/你不需要提前生成它们,你可以根据需要生成它们。从任何状态,你都可以计算出你能达到的所有新状态(如我在第一步中所示)。当你得到一个新的状态时,如果你已经访问了该状态(HashSet,Hashmap),你就不需要再访问它了。@Kale,我添加了一些示例代码,展示了你如何懒洋洋地生成该图。然后,您只需使用HashSet/HashMap进行BFS搜索,以避免在搜索解决方案时多次访问同一节点。
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);
            ...
        }
     }
}