有向无环图的最短路径求解算法

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/qq_37653144/article/details/83513386

对于最短路径问题,Dijkstra算法只能求解所有边的权值都是非负的加权有向图,而Bellman-Ford算法虽然可以求解有负权值边的图的最短路径,但效率并不高。对于有向无环图,下面这种基于Dijkstra和拓扑排序的算法可以在线性时间内解决单点最短路径问题,且能够处理负权重的边,甚至能够求出最长路径。

该算法的思想很简单:按照拓扑顺序放松顶点。因为每条边v→w都只会被放松一次,当v被放松时有:dis[w] <= dis[v] + e.weight。在算法结束前该不等式都会成立,因为dis[v]是不会变化的(因为按照拓扑顺序放松顶点,在v被放松后算法不会再处理任何指向v的边)而dis[w]只会变小。因此,在所有从s可达的顶点都被加入到树中后,最短路径的最优性条件也就成立了。

结合拓扑排序算法和Dijkstra算法来求解有向无环图的最短路径可以在和V+E成正比的时间内得出结果。

//带权有向图
struct EdgeWeightedDigraph
{
	size_t V; //顶点数
	size_t E; //边数
	map<int, forward_list<tuple<int, int, double>> adj; //改进后的邻接表,tuple存储的是边集
}

struct Comp
{
	bool operator()(tuple<int, int, double> &a, tuple<int, int, double> &b)
	{
		return get<2>(a) > get<2>(b);
	}
};

vector<int> FindShortestPath(EdgeWeightedDigraph &g)
{
    vector<int> edge(g.V);
    //定义并初始化向量dis[]
    vector<double> dis(g.V, DBL_MAX);
    dis.at(0) = 0.0;

    vector<int> topo = TopologicalSort(g);
    //关于拓扑排序详见https://blog.csdn.net/qq_37653144/article/details/83215196

    for (const int &i : topo)
    {
        //放松顶点
        for (const auto &e : g.adj.at(i))
        {
            if (dis.at(get<0>(e)) + get<2>(e) < dis.at(get<1>(e)))
            {
                dis.at(get<1>(e)) = dis.at(get<0>(e)) + get<2>(e);
                edge.at(g.V) = get<0>(e);
            }
        }
    }
    return edge;
}

猜你喜欢

转载自blog.csdn.net/qq_37653144/article/details/83513386