单源最短路径算法--Dijkstra算法和Bellman-Ford算法

简介:

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;  
}  
复制代码

 

    本文转自阿凡卢博客园博客,原文链接:http://www.cnblogs.com/luxiaoxun/archive/2012/08/04/2623012.html,如需转载请自行联系原作者


相关文章
|
2月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
89 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
2月前
|
存储 算法 程序员
迪杰斯特拉(Dijkstra)算法(C/C++)
迪杰斯特拉(Dijkstra)算法(C/C++)
|
4月前
|
机器学习/深度学习 算法 Java
算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
这篇文章介绍了基于贪婪技术思想的Prim算法和Dijkstra算法,包括它们的伪代码描述、Java源代码实现、时间效率分析,并展示了算法的测试用例结果,使读者对贪婪技术及其应用有了更深入的理解。
算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
|
4月前
|
自然语言处理 算法
HanLP — HMM隐马尔可夫模型 - 路径规划算法 - 求解最短路径 - 维特比(Viterbi)算法
HanLP — HMM隐马尔可夫模型 - 路径规划算法 - 求解最短路径 - 维特比(Viterbi)算法
61 0
HanLP — HMM隐马尔可夫模型 - 路径规划算法 - 求解最短路径 - 维特比(Viterbi)算法
|
4月前
|
算法 定位技术
路径规划算法 - 求解最短路径 - A*(A-Star)算法
路径规划算法 - 求解最短路径 - A*(A-Star)算法
122 0
|
2月前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
7天前
|
算法
基于GA遗传算法的PID控制器参数优化matlab建模与仿真
本项目基于遗传算法(GA)优化PID控制器参数,通过空间状态方程构建控制对象,自定义GA的选择、交叉、变异过程,以提高PID控制性能。与使用通用GA工具箱相比,此方法更灵活、针对性强。MATLAB2022A环境下测试,展示了GA优化前后PID控制效果的显著差异。核心代码实现了遗传算法的迭代优化过程,最终通过适应度函数评估并选择了最优PID参数,显著提升了系统响应速度和稳定性。
|
5天前
|
算法
基于WOA鲸鱼优化的购售电收益与风险评估算法matlab仿真
本研究提出了一种基于鲸鱼优化算法(WOA)的购售电收益与风险评估算法。通过将售电公司购售电收益风险计算公式作为WOA的目标函数,经过迭代优化计算出最优购电策略。实验结果表明,在迭代次数超过10次后,风险价值收益优化值达到1715.1万元的最大值。WOA还确定了中长期市场、现货市场及可再生能源等不同市场的最优购电量,验证了算法的有效性。核心程序使用MATLAB2022a实现,通过多次迭代优化,实现了售电公司收益最大化和风险最小化的目标。
|
2天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于深度学习网络的宝石类型识别算法matlab仿真
本项目利用GoogLeNet深度学习网络进行宝石类型识别,实验包括收集多类宝石图像数据集并按7:1:2比例划分。使用Matlab2022a实现算法,提供含中文注释的完整代码及操作视频。GoogLeNet通过其独特的Inception模块,结合数据增强、学习率调整和正则化等优化手段,有效提升了宝石识别的准确性和效率。
|
8天前
|
算法
基于大爆炸优化算法的PID控制器参数寻优matlab仿真
本研究基于大爆炸优化算法对PID控制器参数进行寻优,并通过Matlab仿真对比优化前后PID控制效果。使用MATLAB2022a实现核心程序,展示了算法迭代过程及最优PID参数的求解。大爆炸优化算法通过模拟宇宙大爆炸和大收缩过程,在搜索空间中迭代寻找全局最优解,特别适用于PID参数优化,提升控制系统性能。