Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 在邻接列表中查找最长路径_C_Sorting_Traversal_Adjacency List - Fatal编程技术网

C 在邻接列表中查找最长路径

C 在邻接列表中查找最长路径,c,sorting,traversal,adjacency-list,C,Sorting,Traversal,Adjacency List,我有一个邻接列表,我已经为一个给定的带有节点和加权边的图创建了邻接列表。我试图找出在图中找到最长路径的最佳方法。我有一个拓扑排序方法,我听说它很有用,但我不确定如何实现它来找到最长的路径。那么,有没有一种方法可以使用拓扑排序来实现这一点,或者有没有一种更有效的方法 下面是一个调整列表的my out示例(括号中的值是在箭头(成本)到达->节点后到达节点的成本): Node 0 (4)->1(9)->2 Node 1 (10)->3 Node 2 (8)->3 Node 3

我有一个邻接列表,我已经为一个给定的带有节点和加权边的图创建了邻接列表。我试图找出在图中找到最长路径的最佳方法。我有一个拓扑排序方法,我听说它很有用,但我不确定如何实现它来找到最长的路径。那么,有没有一种方法可以使用拓扑排序来实现这一点,或者有没有一种更有效的方法

下面是一个调整列表的my out示例(括号中的值是在箭头
(成本)到达->节点后到达节点的成本):

Node 0 (4)->1(9)->2
Node 1 (10)->3
Node 2 (8)->3
Node 3
Node 4 (3)->8(3)->7
Node 5 (2)->8(4)->7(2)->0
Node 6 (2)->7(1)->0
Node 7 (5)->9(6)->1(4)->2
Node 8 (6)->9(5)->1
Node 9 (7)->3
Node 10 (12)->4(11)->5(1)->6

假设你的图没有圈,否则最长路径会成为一个模糊的概念,你确实可以有一个拓扑排序。现在你可以遍历这个拓扑排序,通过查看每个节点的所有前辈,计算出它与源节点之间的最长距离,并将连接到它们的边的权重与它们的距离相加。然后选择为该节点提供最长距离的e前置。拓扑排序保证所有前置都已正确确定其距离


如果除了最长路径的长度之外,您还需要路径本身。然后从给出最长长度的节点开始,查看其所有前辈,以找到导致此长度的节点。然后重复此过程,直到找到图形的源节点。

假设您的图形没有循环,否则longst path变成了一个模糊的概念,你确实可以有一个拓扑排序。现在你可以遍历这个拓扑排序,通过查看每个节点的所有前置节点,计算出它与源节点之间的最长距离,并将连接到它们的边的权重与它们的距离相加。然后选择给你最长距离的前置节点此节点。拓扑排序保证所有前置节点的距离都已正确确定


如果除了最长路径的长度之外,您还需要路径本身。然后从给出最长长度的节点开始,查看其所有前辈,以找到导致此长度的节点。然后重复此过程,直到找到图形的源节点。

Bryan已经回答了您上面的问题,但我我想我可以深入一点

首先,正如他指出的,这个问题只有在没有循环的情况下才容易解决。如果有循环,你会遇到无限长路径的情况。在这种情况下,你可能会将最长路径定义为没有重复节点的任何路径。不幸的是,这个问题可能是NP难的。因此,我们将重点放在pr上看起来你实际上需要解决的问题(因为你提到了拓扑排序)——有向无环图(DAG)中的最长路径。我们还将假设有两个节点
s
t
,这两个节点是我们的开始和结束节点。除非您可以对图形进行某些假设,否则问题会更糟糕。如果您理解下面的文本,并且图形中的这些假设是正确的,那么您可能可以删除
s
t限制(否则,必须在图形中的每对顶点上运行它!慢…)

该算法的第一步是对顶点进行拓扑排序。直观地说,这是有意义的。假设您从左到右对顶点进行排序(即,最左边的节点将没有传入边)。从
s
t
的最长路径通常从左侧开始,在右侧结束。路径也不可能一直向左。这为您提供了生成最长路径的顺序—从左侧开始,然后向右移动

下一步是从左到右依次定义每个节点的最长路径。对于没有传入边的任何节点,到该节点的最长路径为0(根据定义,这是正确的)。对于具有传入边的任何节点,递归地将到该节点的最长路径定义为所有传入边上的最大值+到达“传入”邻居的最长路径(请注意,例如,如果所有传入边均为负值,则该数字可能为负值!)。直观地说,这是有意义的,但证明也很简单:

假设我们的算法声称到某个节点
v
的最长路径是
d
,但实际的最长路径是某个
d>d
。选择“最少”的节点
v
(我们使用拓扑排序定义的顺序。换句话说,我们选择“最左边的”我们的算法失败的节点。这一点很重要,因此我们可以假设我们的算法已正确确定
v
“左侧”任何节点的最长路径)。将假设最长路径的长度定义为
d'=d_1+e
,其中
d_1
是到节点
v_prev
的假设路径的长度,具有边
e
v
(请注意粗率的命名。边
e
也具有权重
e
)我们可以这样定义它,因为任何到
v
的路径都必须经过它的一个邻居,这个邻居有一条到
v
的边(因为你不可能不通过到达它的边就到达
v
),那么
d\u 1
必须是到
v\u-prev
的最长路径(否则就是矛盾。有一条较长的路径与我们选择的
v
作为“最小”节点相矛盾!)我们的算法会根据需要选择包含
d_1+e
的路径

要生成实际路径,您可以找出使用了哪条边。假设您已将路径重建到路径长度最长的某个顶点
v
。然后检查所有传入顶点,找到路径长度最长的顶点
d'=d-e
,其中
e
是进入
的边的权重v
。您可以
public List<Nodes> FindLongestPath(Graph graph, Node start, Node end)
{
    var longestPathLengths = Dictionary<Node, int>;

    var orderedNodes = graph.Nodes.TopologicallySort();
    // Remove any nodes that are topologically less than start. 
    // They cannot be in a path from start to end by definition
    while (orderedNodes.Pop() != start);
    // Push it back onto the top of the stack
    orderedNodes.Push(start);

    // Do algorithm until we process the end node
    while (1)
    {
        var node = orderedNodes.Pop();
        if (node.IncomingEdges.Count() == 0)
        {
            longestPathLengths.Add(node, 0);
        }
        else
        {
            var longestPathLength = Int.Min;
            foreach (var incomingEdge in node.IncomingEdges)
            {
                var currPathLength = longestPaths[incomingEdge.Parent] +               
                                     incomingEdge.Weight);
                if (currPathlength > longestPathLength)
                {
                    longestPath = currPathLength;
                }
            }

            longestPathLengths.Add(node, longestPath);
        }

        if (node == end)
        {
            break;
        }
    }

    // Reconstruct path. Go backwards until we hit start
    var node = end;
    var longestPath = new List<Node>();
    while (node != start)
    {
        foreach (var incomingEdge in node.IncomingEdges)
        {
            if (longestPathLengths[incomingEdge.Parent] == 
                    longestPathLengths[node] - incomingEdge.Weight)
            {
                longestPath.Prepend(incomingEdge.Parent);
                node = incomingEdge.Parent;
                break;
            }
        }
    }

    return longestPath;
}