贪心算法——单源最短路径(Dijkstra算法)

来源:互联网 发布:exe一机一码加密软件 编辑:程序博客网 时间:2024/05/16 14:31

关于贪心算法介绍:
http://blog.csdn.net/mind_v/article/details/72956707

单源最短路径——Dijkstra算法

问题描述

对于给定的加权有向图G(加权邻接数组表示),它的每一条边(i,j)都有一个固定成本(权值)a[i][j],一条路径的长度就是该路径上所有边的的成本之和。如下图所示,路径124的长度是8,路径125的长度是9。
寻找一条从给定的一个源顶点出发到任意顶点的(目的顶点)的最短路径。如1到5的最短路径为1345。

这里写图片描述

贪心法求解

根据贪婪法,每一步生成一条当前顶点的最短路径。每一条最短路径的目的顶点的选择方法依据贪婪准则:从一条最短路径还没有到达的顶点中,选择一个可以产生最短路径的目的顶点。

我们定义distanceFromSource[i]是在已生成的最短路径上再拓展一条最短边而到达顶点i时的最短路径长度。最开始,只有一条从sourceVertex到sourceVertex的路径,长度为0。这是对于每一个顶点,distanceFromSource[i]等于a[sourceVertex][i]。为产生下一条路径,需要选择一个还没最短路径到达的顶点,在这些顶点中,使distanceFromSource[]值最小的顶点就是下一条路径的终点。当得到一条最短路径之后,有些顶点的的distanceFromSource[]值可能会改变,因为由新的最短路径拓展可能得到更小的值。

算法步骤:
1)初始化distanceFromSource[i]=a[sourceVertex][i](1<= i <= n)
对所有邻接于sourceVertex的顶点i,令prodecesoor[i]=sourceVertex
对所有的其他顶点,predecessor[sourceVertex]=0,predecessor[i]=-1
创建一个newReachableVertices,存储所有predecessor[i]>0的顶点(即这个表包含所有邻接于sourceVertex的顶点)。

2)如果newReachableVertices为空,算法终止,否则转置3)

3)从newReachableVertices中删除distanceFromSource值最小的i

4)对所有邻接于i的顶点j,将distanceFromSource[j]更新min{distanceFromSource[j],distanceFromSource[i]+a[i][j]}。如果distanceFromSource[j]改变,令predecessor[j]=i,而且若j没有在newReachableVertices`中,则将其加入进去。

注:newReachableVertices是一个链表对象,使用到的接口包括:
insert(index, element):在指定索引位置插入元素element的节点;
eraseElement(element):删除指定的元素节点;
begin():返回第一个元素的迭代器
end():返回最后一个元素后一个位置的迭代器

C++实现:

void shortestPaths(int sourceVertex, int *distanceFromSource, int numberOfVertices){//寻找从源顶点开始的最短路径 //从数组distanceFromSource中返回最短路径 //在数组predecessor中返回顶点在路径上的前驱的信息    if (sourceVertex < 1 || sourceVertex > n)        throw illegalParameterValue("Invalid source Vertex");    //确定是加权图    if (!weighted())        return;    chain<int> newReachableVertices;    for (int i = 1; i <= n; ++i)    {        distanceFromSource[i] = a[sourceVertex][i];        if (distanceFromSource[i] == noEdge)            distanceFromSource[i] = -1;        else        {            predecessor[i] = sourceVertex;            newReachableVertices.insert(0, i);        }    }    distanceFromSource[sourceVertex] = 0;    Predecessor[sourceVertex] = 0;    //更新distanceFromSource和predecessor    while (!newReachableVertices.empty())    {//还存在更多的路径     //寻找distanceFromSource值最小的,还未达到的顶点v        chain<T>::iterator iNewReachableVertices = newReachableVertices.begin();        chain<T>::iterator end = newReachableVertices.end();        int v = *iNewReachableVertices;        iNewReachableVertices++;        while (iNewReachableVertices != end)        {            int w = *iNewReachableVertices;            iNewReachableVertices++;            if (distanceFromSource[w] < distanceFromSource[v])                v = w;        }        //下一条最短路径到达v        //先从newReachableVertices中删除v,然后更新distanceFromSource        for (int j = 1; j <= n; ++j)        {            if (a[v][j] != noEdge && (predecessor[j] == -1 ||                distanceFromSource[j] > distanceFromSource[v] + a[v][j]))            {                //distanceFromSource[j]减少                distanceFromSource[j] = distanceFromSource[v] + a[v][j];                if (predecessor[j] == -1)                    //以前未到达,加入j                    newReachableVertices.insert(0, j);                predecessor[j] = v;            }        }       }}

使用邻接矩阵描述图时,第一个while循环的复杂度为O(n),第二个while循环和for循环都要达到所有的顶点,故也为O(n),所以整个算法的时间复杂度为O(n2)。

原创粉丝点击