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

来源:互联网 发布:黑河广电网络 编辑:程序博客网 时间:2024/05/22 04:49

第一次看见这个问题是 《算法导论》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 <iostream>#include <vector>#include <stack>#include <map>#include <cstring>#include <string>#include <algorithm>//#include <cmath> #include <utility>#include <unordered_map>#include <set>#include <queue>#include <cmath>#include <list>#include <functional>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<AdjListNode> *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<AdjListNode>[v];}//Dfs求其拓扑排序void Graph::TopologicalSortUtil(int v, bool visited[], stack<int> &Stack) {    visited[v] = true;    list<AdjListNode>::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<AdjListNode>::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.很少写这种面向对象的代码,所以写一写练习一下。

原创粉丝点击