📜  有向无环图中的最长路径|设置 2

📅  最后修改于: 2022-05-13 01:57:54.468000             🧑  作者: Mango

有向无环图中的最长路径|设置 2

给定一个加权有向无环图 (DAG) 和其中的一个源顶点,找出给定图中从源顶点到所有其他顶点的最长距离。

我们已经讨论了如何在 Set 1 中找到有向无环图 (DAG) 中的最长路径。在这篇文章中,我们将讨论另一种有趣的解决方案来找到 DAG 的最长路径,它使用算法在 DAG 中找到最短路径。
这个想法是否定路径的权重并找到图中的最短路径。加权图 G 中两个给定顶点 s 和 t 之间的最长路径与图 G' 中的最短路径相同,该最短路径是通过将每个权重更改为其否定而从 G 导出的。因此,如果最短路径可以在 G' 中找到,那么最长路径也可以在 G 中找到。
以下是寻找最长路径的分步过程 -

我们将给定图的每条边的权重更改为其否定,并将到所有顶点的距离初始化为无限,将到源的距离初始化为 0,然后我们找到表示图的线性排序的图的拓扑排序。当我们以拓扑顺序考虑顶点 u 时,可以保证我们已经考虑了它的每条传入边。即我们已经找到了到该顶点的最短路径,我们可以使用该信息来更新其所有相邻顶点的较短路径。一旦我们有了拓扑顺序,我们就按照拓扑顺序一个一个地处理所有顶点。对于每个正在处理的顶点,我们使用当前顶点与源顶点的最短距离及其边权重来更新其相邻顶点的距离。 IE

for every adjacent vertex v of every vertex u in topological order
    if (dist[v] > dist[u] + weight(u, v))
    dist[v] = dist[u] + weight(u, v)

一旦我们从源顶点找到所有最短路径,最长路径将只是最短路径的否定。

下面是上述方法的实现:

C++
// A C++ program to find single source longest distances
// in a DAG
#include 
using namespace std;
 
// Graph is represented using adjacency list. Every node of
// adjacency list contains vertex number of the vertex to
// which edge connects. It also contains weight of the edge
class AdjListNode
{
    int v;
    int weight;
public:
    AdjListNode(int _v, int _w)
    {
        v = _v;
        weight = _w;
    }
    int getV()
    {
        return v;
    }
    int getWeight()
    {
        return weight;
    }
};
 
// Graph class represents a directed graph using adjacency
// list representation
class Graph
{
    int V; // No. of vertices
 
    // Pointer to an array containing adjacency lists
    list* adj;
 
    // This function uses DFS
    void longestPathUtil(int, vector &, stack &);
public:
    Graph(int); // Constructor
    ~Graph();   // Destructor
 
    // function to add an edge to graph
    void addEdge(int, int, int);
 
    void longestPath(int);
};
 
Graph::Graph(int V) // Constructor
{
    this->V = V;
    adj = new list[V];
}
 
Graph::~Graph() // Destructor
{
    delete[] adj;
}
 
void Graph::addEdge(int u, int v, int weight)
{
    AdjListNode node(v, weight);
    adj[u].push_back(node); // Add v to u's list
}
 
// A recursive function used by longestPath. See below
// link for details.
// https://www.geeksforgeeks.org/topological-sorting/
void Graph::longestPathUtil(int v, vector &visited,
                            stack &Stack)
{
    // Mark the current node as visited
    visited[v] = true;
 
    // Recur for all the vertices adjacent to this vertex
    for (AdjListNode node : adj[v])
    {
        if (!visited[node.getV()])
            longestPathUtil(node.getV(), visited, Stack);
    }
 
    // Push current vertex to stack which stores topological
    // sort
    Stack.push(v);
}
 
// The function do Topological Sort and finds longest
// distances from given source vertex
void Graph::longestPath(int s)
{
    // Initialize distances to all vertices as infinite and
    // distance to source as 0
    int dist[V];
    for (int i = 0; i < V; i++)
        dist[i] = INT_MAX;
    dist[s] = 0;
 
    stack Stack;
 
    // Mark all the vertices as not visited
    vector visited(V, false);
 
    for (int i = 0; i < V; i++)
        if (visited[i] == false)
            longestPathUtil(i, visited, Stack);
 
    // Process vertices in topological order
    while (!Stack.empty())
    {
        // Get the next vertex from topological order
        int u = Stack.top();
        Stack.pop();
 
        if (dist[u] != INT_MAX)
        {
            // Update distances of all adjacent vertices
            // (edge from u -> v exists)
            for (AdjListNode v : adj[u])
            {
                // consider negative weight of edges and
                // find shortest path
                if (dist[v.getV()] > dist[u] + v.getWeight() * -1)
                    dist[v.getV()] = dist[u] + v.getWeight() * -1;
            }
        }
    }
 
    // Print the calculated longest distances
    for (int i = 0; i < V; i++)
    {
        if (dist[i] == INT_MAX)
            cout << "INT_MIN ";
        else
            cout << (dist[i] * -1) << " ";
    }
}
 
// Driver code
int main()
{
    Graph g(6);
 
    g.addEdge(0, 1, 5);
    g.addEdge(0, 2, 3);
    g.addEdge(1, 3, 6);
    g.addEdge(1, 2, 2);
    g.addEdge(2, 4, 4);
    g.addEdge(2, 5, 2);
    g.addEdge(2, 3, 7);
    g.addEdge(3, 5, 1);
    g.addEdge(3, 4, -1);
    g.addEdge(4, 5, -2);
 
    int s = 1;
 
    cout << "Following are longest distances from "
         << "source vertex " << s << " \n";
    g.longestPath(s);
 
    return 0;
}


Python3
# A Python3 program to find single source
# longest distances in a DAG
import sys
 
def addEdge(u, v, w):
     
    global adj
    adj[u].append([v, w])
 
# A recursive function used by longestPath.
# See below link for details.
# https:#www.geeksforgeeks.org/topological-sorting/
def longestPathUtil(v):
     
    global visited, adj,Stack
    visited[v] = 1
 
    # Recur for all the vertices adjacent
    # to this vertex
    for node in adj[v]:
        if (not visited[node[0]]):
            longestPathUtil(node[0])
 
    # Push current vertex to stack which
    # stores topological sort
    Stack.append(v)
 
# The function do Topological Sort and finds
# longest distances from given source vertex
def longestPath(s):
     
    # Initialize distances to all vertices
    # as infinite and
    global visited, Stack, adj,V
    dist = [sys.maxsize for i in range(V)]
    # for (i = 0 i < V i++)
    #     dist[i] = INT_MAX
    dist[s] = 0
 
    for i in range(V):
        if (visited[i] == 0):
            longestPathUtil(i)
 
    # print(Stack)
    while (len(Stack) > 0):
         
        # Get the next vertex from topological order
        u = Stack[-1]
        del Stack[-1]
 
        if (dist[u] != sys.maxsize):
             
            # Update distances of all adjacent vertices
            # (edge from u -> v exists)
            for v in adj[u]:
                 
                # Consider negative weight of edges and
                # find shortest path
                if (dist[v[0]] > dist[u] + v[1] * -1):
                    dist[v[0]] = dist[u] + v[1] * -1
 
    # Print the calculated longest distances
    for i in range(V):
        if (dist[i] == sys.maxsize):
            print("INT_MIN ", end = " ")
        else:
            print(dist[i] * (-1), end = " ")
 
# Driver code
if __name__ == '__main__':
     
    V = 6
    visited = [0 for i in range(7)]
    Stack = []
    adj = [[] for i in range(7)]
 
    addEdge(0, 1, 5)
    addEdge(0, 2, 3)
    addEdge(1, 3, 6)
    addEdge(1, 2, 2)
    addEdge(2, 4, 4)
    addEdge(2, 5, 2)
    addEdge(2, 3, 7)
    addEdge(3, 5, 1)
    addEdge(3, 4, -1)
    addEdge(4, 5, -2)
 
    s = 1
 
    print("Following are longest distances from source vertex", s)
     
    longestPath(s)
 
# This code is contributed by mohit kumar 29


输出:

Following are longest distances from source vertex 1 
INT_MIN 0 2 9 8 10 

时间复杂度:拓扑排序的时间复杂度为 O(V + E)。找到拓扑顺序后,算法处理所有顶点,并且对于每个顶点,它对所有相邻顶点运行一个循环。由于图中的相邻顶点总数为 O(E),因此内部循环运行 O(V + E) 次。因此,该算法的整体时间复杂度为 O(V + E)。