Longest Path in DAG 有向无环图中的最长路径问题

第一次看见这个问题是 《算法导论》Chapter 15 动态规划课后思考题15-1的题目。
本文主要参考:http://www.geeksforgeeks.org/find-longest-path-directed-acyclic-graph/

问题描述

给定一个有向图(Directed Acyclic Graph)以及一个起点s,求该图中s点到其余所有点的最长路径。

题解

正如算法导论中提到的那样,给定有向图的最长路径问题并不如有向图最短路径那么简单,因为它不具备 最优子结构(Optimal Substructure Property)。实际上,该问题是NP-Hard问题。
但是,有向无环图的最长路径问题确有一个线性时间的解。这种思想和解决DAG最短路径问题相似,采用拓扑排序(Topological Sorting )。
我们将求得DAG的拓扑序列,那么对于拓扑序列,就可以用动态规划来处理。由拓扑序列的性质可以断定在拓扑序列该问题具有最优子结构。(当前问题的解包含子问题的解)
我们定义dist[v]为起点s到v的最长路径,那么递归关系为:

dist[v] = max{dist[pre] + weight(pre->v)},pre是一条指向v的边的起点

这里我们从左到右遍历拓扑序列,对于当前点i,更新其邻接点的dist。
需要强调的是这里的拓扑排序的实现方式是基于Dfs,需要掌握。

代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#include  
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
//定义邻接点类
class AdjListNode {
    int val;
    int weight;

public:
    AdjListNode(int _v, int _w) {
        val = _v;
        weight = _w;
    }
    int getV() { return val; }
    int getWeight() { return weight; }
};
//定义图类
class Graph {
    int num_v;
    list *adj;
    void TopologicalSortUtil(int v, bool visited[], stack<int> &Stack);
public:
    Graph(int v);
    void addEdge(int u, int v, int weight);
    void LongestPath(int s);
};

Graph::Graph(int v) {
    num_v = v;
    adj = new list[v];
}
//Dfs求其拓扑排序
void Graph::TopologicalSortUtil(int v, bool visited[], stack<int> &Stack) {
    visited[v] = true;
    list::iterator i;
    for (i = adj[v].begin(); i != adj[v].end(); i++) {
        if (visited[(*i).getV()] == true) continue;
        TopologicalSortUtil((*i).getV(), visited, Stack);
    }
    Stack.push(v);
}

void Graph::addEdge(int u, int v, int weight) {
    AdjListNode next(v, weight);
    adj[u].push_back(next);
}

void Graph::LongestPath(int s) {
    bool *visited = new bool[num_v];
    int *dist = new int[num_v];
    stack<int> Stack;
    for (int i = 0; i < num_v; i++) {
        visited[i] = false;
        dist[i] = INT_MIN;
    }
    //初始化所有dist为INT_MIN,然后dist[s] = 0.
    dist[s] = 0;
    //求其拓扑序列
    for (int i = 0; i < num_v; i++) {
        if (!visited[i]) {
            TopologicalSortUtil(i, visited, Stack);
        }
    }

    while (!Stack.empty()) {
        int u = Stack.top();
        Stack.pop();
        if (dist[u] == INT_MIN) continue;//如果此时仍不可达,则跳过该点
        list::iterator i;
        for (i = adj[u].begin(); i != adj[u].end(); i++) {
            if (dist[(*i).getV()] < dist[u] + (*i).getWeight()) {
                dist[(*i).getV()] = dist[u] + (*i).getWeight();
            }
        }
    }
    for (int i = 0; i < num_v; i++) {
        if (i) printf(" ");
        (dist[i] == INT_MIN) ? printf("INF") : printf("%d", dist[i]);
    }

}



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 distacnes from soucre vertex " << s << "\n";
    g.LongestPath(s);
    return 0;
}

总结

写这篇博文目的:
1.Dfs外加一个for循环求DAG的拓扑排序。
2.很少写这种面向对象的代码,所以写一写练习一下。

你可能感兴趣的:(Longest Path in DAG 有向无环图中的最长路径问题)