zoukankan      html  css  js  c++  java
  • 单源最短路径算法Dijkstra算法和BellmanFord算法

    Dijkstra算法

    算法流程:
    (a) 初始化:用起点v到该顶点w的直接边(弧)初始化最短路径,否则设为∞;
    (b) 从未求得最短路径的终点中选择路径长度最小的终点u:即求得v到u的最短路径;
    (c) 修改最短路径:计算u的邻接点的最短路径,若(v,…,u)+(u,w)<(v,…,w),则以(v,…,u,w)代替。
    (d) 重复(b)-(c),直到求得v到其余所有顶点的最短路径。
    特点:总是按照从小到大的顺序求得最短路径。

    假设一共有N个节点,出发结点为s,需要一个一维数组prev[N]来记录前一个节点序号,一个一维数组dist[N]来记录从原点到当前节点最短路径(初始值为s到Vi的边的权值,没有则为+∞),一个二维数组weights[N][N]来记录各点之间边的权重,按以上流程更新prev[N]和dist[N]。

    参考代码:

    #include <iostream>   
    #include <cstdlib>   
    using namespace std;  
      
    void Dijkstra(int n,int s,int *dist,int *prev,int w[][4])  
    {  
        int maxint = 65535;  
        bool *visit = new bool[n];  
      
        for (int i = 0; i < n; i++)  
        {  
            dist[i] = w[s][i];  
            visit[i] = false;  
            if (dist[i] != maxint)  
            {  
                prev[i] = s;  
            }  
        }  
      
        dist[s] = 0;  
        visit[s] = true;  
        for (int i = 0; i < n; i++)  
        {  
            int temp = maxint;  
            int u = s;  
            for (int j = 0; j < n; j++)  
            {  
                if ((!visit[j]) && (dist[j] < temp))  
                {  
                    u = j;  
                    temp = dist[j];  
                }  
            }  
            visit[u] = true;  
            for (int j = 0; j < n; j++)  
            {  
                if (!visit[j])  
                {  
                    int newdist = dist[u] + w[u][j];  
                    if (newdist < dist[j])  
                    {  
                        dist[j] = newdist;  
                        prev[j] = u;  
                    }  
                }  
            }  
        }  
      
        delete []visit;  
    }  
      
    int main()  
    {  
        int n,v,u;  
        int weight[4][4]={  
            0,2,65535,4,  
            2,0,3,65535,  
            65535,3,0,2,  
            4,65535,2,0  
            };  
        int q = 0;  
        int way[4];  
        int dist[4];  
        int prev[4];  
        int s = 1;  
        int d = 3;  
        Dijkstra(4, s, dist, prev, weight);  
        cout<<"The least distance from "<<s<<" to "<<d<<" is "<<dist[d]<<endl;  
        int w = d;  
        while (w != s)  
        {  
            way[q++] = prev[w];  
            w = prev[w];  
        }  
        cout<<"The path is ";  
        for (int j = q-1; j >= 0; j--)  
        {  
            cout<<way[j]<<" ->";  
        }  
        cout<<d<<endl;  
      
        return 0;  
    }  

    Bellman-Ford算法

    Bellman-Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题。对于给定的带权(有向或无向)图 G=(V,E),其源点为s,加权函数 w 是边集 E 的映射。对图G运行Bellman-Ford算法的结果是一个布尔值,表明图中是否存在着一个从源点s可达的负权回路。若不存在这样的回路,算法将给出从源点s到图G的任意顶点v的最短路径d[v]。

    Bellman-Ford算法流程分为三个阶段:

    (1)初始化:将除源点外的所有顶点的最短距离估计值 d[v] ←+∞, d[s] ←0;
    (2)迭代求解:反复对边集E中的每条边进行松弛操作,使得顶点集V中的每个顶点v的最短距离估计值逐步逼近其最短距离;(运行|v|-1次)
    (3)检验负权回路:判断边集E中的每一条边的两个端点是否收敛。如果存在未收敛的顶点,则算法返回false,表明问题无解;否则算法返回true,并且从源点可达的顶点v的最短距离保存在 d[v]中。

    算法描述如下:

    Bellman-Ford(G,w,s) :boolean   //图G ,边集 函数 w ,s为源点
    1        for each vertex v ∈ V(G) do        //初始化 1阶段
    2            d[v] ←+∞
    3        d[s] ←0;                            //1阶段结束
    4        for i=1 to |v|-1 do                  //2阶段开始,双重循环。
    5           for each edge(u,v) ∈E(G) do    //边集数组要用到,穷举每条边。
    6              If d[v]> d[u]+ w(u,v) then     //松弛判断
    7                 d[v]=d[u]+w(u,v)            //松弛操作   2阶段结束
    8        for each edge(u,v) ∈E(G) do
    9            If d[v]> d[u]+ w(u,v) then
    10            Exit false
    11    Exit true

    适用条件和范围:
      1.单源最短路径(从源点s到其它所有顶点v);
      2.有向图&无向图(无向图可以看作(u,v),(v,u)同属于边集E的有向图);
      3.边权可正可负(如有负权回路输出错误提示);
      4.差分约束系统;

    #include <stdio.h>   
    #include <stdlib.h>   
      
    /* Let INFINITY be an integer value not likely to be 
       confused with a real weight, even a negative one. */  
         
    #define INFINITY ((1 << 14)-1)   
      
    typedef struct   
    {  
        int source;  
        int dest;  
        int weight;  
    } Edge;  
      
    void BellmanFord(Edge edges[], int edgecount, int nodecount, int source)  
    {  
        int *distance =(int*) malloc(nodecount*sizeof(int));  
        int i, j;  
      
        for (i=0; i < nodecount; ++i)  
           distance[i] = INFINITY;  
        distance[source] = 0;  
      
        for (i=0; i < nodecount; ++i)   
        {  
           int nbChanges = 0;   
           for (j=0; j < edgecount; ++j)   
           {  
                if (distance[edges[j].source] != INFINITY)   
                {  
                    int new_distance = distance[edges[j].source] + edges[j].weight;  
                    if (new_distance < distance[edges[j].dest])   
                    {  
                      distance[edges[j].dest] = new_distance;  
                      nbChanges++;   
                    }   
                }  
            }  
             // if one iteration had no impact, further iterations will have no impact either   
            if (nbChanges == 0) break;   
        }  
      
        for (i=0; i < edgecount; ++i)   
        {  
            if (distance[edges[i].dest] > distance[edges[i].source] + edges[i].weight)   
            {  
                puts("Negative edge weight cycles detected!");  
                free(distance);  
                return;  
            }  
        }  
      
        for (i=0; i < nodecount; ++i)   
        {  
            printf("The shortest distance between nodes %d and %d is %d\n", source, i, distance[i]);  
        }  
      
        free(distance);  
        return;  
    }  
      
    int main(void)  
    {  
        /* This test case should produce the distances 2, 4, 7, -2, and 0. */  
        Edge edges[10] = {{0,1, 5}, {0,2, 8}, {0,3, -4}, {1,0, -2},  
                          {2,1, -3}, {2,3, 9}, {3,1, 7}, {3,4, 2},  
                          {4,0, 6}, {4,2, 7}};  
        BellmanFord(edges, 10, 5, 4);  
        return 0;  
    }  
  • 相关阅读:
    jQuery的遍历方法
    xampp配置host和httpd可以随意访问任何本机的地址
    JavaScript的this简单实用
    移动端rem布局和百分比栅格化布局
    你知道用AngularJs怎么定义指令吗?
    谈谈Angular关于$watch,$apply 以及 $digest的工作原理
    深入了解Angularjs指令中的ngModel
    如何将angularJs项目与requireJs集成
    requireJS(二)
    requireJS(一)
  • 原文地址:https://www.cnblogs.com/luxiaoxun/p/2623012.html
Copyright © 2011-2022 走看看