【问题标题】:Linear Array with nodes randomly linked to other nodes in array, shortest path线性数组,节点随机链接到数组中的其他节点,最短路径
【发布时间】:2010-10-08 10:10:02
【问题描述】:

信息: 我有一个 100 个节点的数组,[0 .. 99]。每个节点可以有任意数量的链接节点:

eg1, 0 链接到 5、10、15、20。 eg2, 1 链接到 30, 40, 50。 eg3等。

所有100个节点至少有一个链接节点,节点不知道谁链接到它们。

问题: 如果提供了 START 和 END,我如何找到最短的链接路径。

例如。 START=5,END=80,链接路径(示例):[5]->10->24->36->[80]?

我正在使用 Pascal 和/或 PHP,但了解我在寻找什么[代码也有帮助]。

【问题讨论】:

  • 有人有家庭作业! ;-)
  • 既然您是在寻求帮助理解,最好能告诉我们您不理解的部分。
  • 尼克——我希望我在学校,这是为了一个爱好游戏。 Rob——我确实(不)不明白如何在不循环整个线性数组的情况下完成这项工作。

标签: php delphi shortest-path


【解决方案1】:

大量阅读/算法: Shortest path problem。您实际上只是让每条边(如您所说的“链接”)具有相同的权重。

【讨论】:

    【解决方案2】:

    从起始节点开始进行广度优先遍历,并在找到结束节点后立即退出。

    【讨论】:

      【解决方案3】:

      这有循环吗?即它是一个有向无环图吗?

      如果没有循环:

         List<Node> GetShortestPath(Node startNode, Node endNode)
         {   
             //If this is the node you are looking for...
             if (startNode.ReferenceEquals(endNode))
             {
                 //return a list with just the end node
                 List<Nodes> result = new List<Nodes>();
                 result.Add(endNode);            
                 return result;
             }
      
             List<Node> bestPath = null;
      
             foreach(Node child in startNode.Children)
             {             
                //get the shortest path from this child
                List<Node> childPath = GetShortestPath(child, endNode);
                if (childPath != null &&
                   ( bestPath == null || childPath.Count < bestPath.Count))
                { 
                    bestPath = childPath;
                }
             }
      
             bestPath.Insert(0, startNode);
             return bestPath;
          }
      

      [编辑:添加了循环示例] 如果可以有循环:

         List<Node> GetShortestPath(Node startNode, Node endNode)
         {
              List<Node> nodesToExclude = new List<Node>();
              return GetShortestPath(startNode, endNOde, nodesToExclude);
         }
      
         List<Node> GetShortestPath(Node startNode, Node endNode, List<Node> nodesToExclude)
         {   
             nodesToExclude.Add(startNode);
      
             List<Node> bestPath = null;
      
             //If this is end node...
             if (startNode.ReferenceEquals(endNode))
             {
                 //return a list with just the child node
                 List<Nodes> result = new List<Nodes>();
                 result.Add(endNode);            
                 return result;
             }
      
             foreach(Node child in startNode.Children)
             {
                if (!nodesToExclude.Contains(child))
                {
                    //get the shortest path from this child
                    List<Node> childPath = GetShortestPath(child, endNode);
                    if (childPath != null &&
                       ( bestPath == null || childPath.Count < bestPath.Count))
                    { 
                        bestPath = childPath;
                    }
                }
             }
      
             nodesToExclude.Remove(startNode);
             bestPath.Insert(0, child);
      
             return bestPath;
          }
      

      【讨论】:

      • 人们认为这是家庭作业,因为他们发现答案很简单,并不是我们所有人实际上都是为一个生活小子、爱好而编写代码!
      【解决方案4】:

      两个结构:一个集合和一个列表。

      在集合中,您存储已经访问过的节点。这会阻止您遵循周期。

      该列表包含以下对象:(1) 一个节点,以及 (2) 一个指向找到它的节点的指针。

      从起始节点开始,将其添加到集合中,将其添加到具有空反向引用的列表中,然后将其可以到达的所有节点添加到具有反向引用到列表中索引 0 的列表中(起始节点)。

      然后对于列表中的每个元素,直到您到达末尾,执行以下操作:

      1. 如果它在集合中已经跳过它(您已经访问过它)并移至列表中的下一个项目。
      2. 否则,将它添加到集合中,并将它可以到达的所有节点添加到列表中,并将反向引用您正在“查看”的索引添加到列表的末尾。然后转到列表中的下一个索引并重复。

      如果您在任何时候到达结束节点(最好是在将其添加到列表时 - 而不是在列表中访问它),通过对起始节点的反向引用进行追溯并反转路径。

      例子:

      给定节点 0 到 3,其中
      节点0 --> 节点1
      节点0 --> 节点2
      节点 1 --> 节点 2
      节点 2 --> 节点 3
      node0 为 START,node3 为 END

      SET = {}
      列表 = []

      第 1 步 - 添加 START:

      SET = {node0}
      LIST = [[node0, null]]

      第 2 步 - 在列表的索引 0 处 - 添加可达节点:

      SET = {node0, node1, node2}
      LIST = [[node0, null], [node1, 0], [node2, 0]]

      第 3 步 - 在 LIST 的索引 1 处 - 添加可达节点:

      node2 已经在 SET 中。跳过将可达节点添加到 LIST。
      SET = {node0, node1, node2}
      LIST = [[node0, null], [node1, 0], [node2, 0]]

      第 4 步 - 在 LIST 的索引 2 处 - 添加可达节点:

      SET = {node0, node1, node2, node3}
      LIST = [[node0, null], [node1, 0], [node2, 0], [node3, 2]]

      第 5 步 - 到达 END,现在回溯:

      插入到 LIST 中的 END 节点(node3)有一个对列表中索引 2 的反向引用,即 node2。这对列表中的索引 0 有一个反向引用,即 node0 (START)。将其反转,您将得到 node0 --> node2 --> node3 的最短路径。

      【讨论】:

        【解决方案5】:

        这是一棵树/图还是一片森林?如果是森林,则路径可能并不总是被定义。如果这是一个树/图,请尝试使用广度优先搜索。

        可以这样想:比如说,您正在执行一项秘密任务,以在附近寻找可爱的小鸡。您从自己的房子开始,并将其标记为开始。你接下来会去敲你最近的邻居,对吧?所以,我们将这样做——将所有连接到队列的节点推入队列中。现在,对该队列中的所有节点重复邻居搜索。并继续这样做,直到你得到你的女孩,呃,END。

        【讨论】:

        • 我想你要问的是图表是连接的还是未连接的。是否是一棵树并不重要。
        • True :) 但我保留了两者以避免另一个问题!
        猜你喜欢
        • 1970-01-01
        • 2017-11-14
        • 2021-12-18
        • 2019-09-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多