Fork me on GitHub

最短路径问题的Dijkstra和SPFA算法总结

Dijkstra算法:

解决带非负权重图的单元最短路径问题。时间复杂度为O(V*V+E)

算法精髓:维持一组节点集合S,从源节点到该集合中的点的最短路径已被找到,算法重复从剩余的节点集V-S中选择最短路径估计最小的节点u,对u的所有连边进行松弛操作。即对j=1~n,dis[j] = min(dis[j],dis[k]+map[k][j])。

常规代码如下:

void Dijkstra()
{
    int i,j,k,mini;
    memset(vis,0,sizeof(vis));
    for(i=1;i<=n;i++)
        d[i] = Mod;
    d[s] = 0;     //源点距离为0
    for(i=1;i<=n;i++)
    {
        mini = Mod;
        for(j=1;j<=n;j++)         //找最短路径估计最小的节点k
        {
            if(!vis[j] && d[j] < mini)
            {
                k = j;
                mini = d[j];
            }
        }
        vis[k] = 1; 
        for(j=1;j<=n;j++)       //松弛操作
        {
            if(mp[k][j] != Mod && d[j] > d[k] + mp[k][j])  //mp[k][j] != Mod 也可写成 !vis[j]
                d[j] = d[k] + mp[k][j];
        }
    }
}
View Code

 

SPFA算法:

实际是用队列优化的Bellman-ford算法,可以允许负边权的存在。SPFA算法通过维护一个队列,使得一个节点的当前最短路径被更新之后没有必要立刻去更新其他的节点,从而大大减少了重复的操作次数。在负边权和稀疏图上可完全替代Bellman-ford算法,但是与Dijkstra算法与Bellman-ford算法都不同,SPFA的算法时间效率是不稳定的,即它对于不同的图所需要的时间有很大的差别。在非负边权上最好还是用性能稳定的Dijkstra算法。时间复杂度O(kE){k<<V}。

常规代码如下:

//边用vector<pait<int,int> > 存储
void SPFA(int s)
{
    int u,v,i;
    int len;
    for(i=0;i<=n;i++)
    {
        inq[i] = 0;
        dis[i] = Mod;
    }
    dis[s] = 0;
    while(!que.empty())
        que.pop();
    que.push(s);
    while(!que.empty())
    {
        u = que.front();
        que.pop();
        inq[u] = 0;
        for(i=0;i<edge[u].size();i++)
        {
            v = edge[u][i].first;
            len = edge[u][i].second;
            if(dis[v] > len + dis[u])
            {
                dis[v] = len + dis[u];
                if(!inq[v])
                {
                    inq[v] = 1;
                    que.push(v);
                }
            }
        }
    }
}
View Code

 

 

posted @ 2014-03-26 14:25 whatbeg 阅读(...) 评论(...) 编辑 收藏