最短路径之Bellman_Ford

来源:互联网 发布:打谱软件overture教程 编辑:程序博客网 时间:2024/05/18 01:19

适用于:

单源最短路径(从源点s到其它所有顶点v);

有向图&无向图(无向图可以看作(u,v),(v,u)同属于边集E的有向图);

边权可正可负(如有负权回路输出错误提示);

差分约束系统;

Bellman-Ford算法的流程如下:
给定图G(V, E)(其中VE分别为图G的顶点集与边集),源点s数组Distant[i]记录从源点s到顶点i的路径长度,初始化数组Distant[n]为inf, Distant[s]0

以下操作循环执行至多n-1次,n为顶点数:
对于每一条边e(u, v),如果Distant[u] + w(u, v) < Distant[v],则另Distant[v] = Distant[u]+w(u, v)w(u, v)为边e(u,v)的权值;
若上述操作没有对Distant进行更新,说明最短路径已经查找完毕,或者部分点不可达,跳出循环。否则执行下次循环;

为了检测图中是否存在负环路,即权值之和小于0的环路。对于每一条边e(u, v),如果存在Distant[u] + w(u, v) < Distant[v]的边,则图中存在负环路,即是说改图无法求出单源最短路径。否则数组Distant[n]中记录的就是源点s到各顶点的最短路径长度。

可知,Bellman-Ford算法寻找单源最短路径的时间复杂度为O(V*E).

BellmanFord算法可以大致分为三个部分
第一,初始化所有点。每一个点保存一个值,表示从原点到达这个点的距离,将原点的值设为0,其它的点的值设为无穷大(表示不可达)。
第二,进行循环,循环下标为从1n1n等于图中点的个数)。在循环内部,遍历所有的边,进行松弛计算。
第三,遍历途中所有的边(edgeuv)),判断是否存在这样情况:
dv) > d (u) + w(u,v)
则返回false,表示途中存在从源点可达的权为负的回路。
 
之所以需要第三部分的原因,是因为,如果存在从源点可达的权为负的回路。则 应为无法收敛而导致不能求出最短路径。

但是要注意有的题目会有重复的边,比如这个题:Til the Cows Come Home  题解:点击打开链接

bool Bellman_Ford()  {      for(int i = 1; i <= nodenum; ++i) //初始化          dis[i] = (i == original ? 0 : MAX);      for(int i = 1; i <= nodenum - 1; ++i)          for(int j = 1; j <= edgenum; ++j)              if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛            {                  dis[edge[j].v] = dis[edge[j].u] + edge[j].cost;              }              bool flag = 1; //判断是否含有负权回路              for(int i = 1; i <= edgenum; ++i)                  if(dis[edge[i].v] > dis[edge[i].u] + edge[i].cost)                  {                      flag = 0;                      break;                  }                  return flag;  } 


#include <iostream>using namespace std;const int maxnum = 100;const int maxint = 99999; // 边,typedef struct Edge{    int u, v;    // 起点,重点    int weight;  // 边的权值}Edge; Edge edge[maxnum];     // 保存边的值int  dist[maxnum];     // 结点到源点最小距离 int nodenum, edgenum, source;    // 结点数,边数,源点 // 初始化图void init(){    // 输入结点数,边数,源点    cin >> nodenum >> edgenum >> source;    for(int i=1; i<=nodenum; ++i)        dist[i] = maxint;    dist[source] = 0;    for(int i=1; i<=edgenum; ++i)    {        cin >> edge[i].u >> edge[i].v >> edge[i].weight;        if(edge[i].u == source)          //注意这里设置初始情况            dist[edge[i].v] = edge[i].weight;    }} // 松弛计算void relax(int u, int v, int weight){    if(dist[v] > dist[u] + weight)        dist[v] = dist[u] + weight;} bool Bellman_Ford(){    for(int i=1; i<=nodenum-1; ++i)        for(int j=1; j<=edgenum; ++j)            relax(edge[j].u, edge[j].v, edge[j].weight);    bool flag = 1;    // 判断是否有负环路    for(int i=1; i<=edgenum; ++i)        if(dist[edge[i].v] > dist[edge[i].u] + edge[i].weight)        {            flag = 0;            break;        }    return flag;}int main(){    //freopen("input3.txt", "r", stdin);    init();    if(Bellman_Ford())        for(int i = 1 ;i <= nodenum; i++)            cout << dist[i] << endl;    return 0;}



原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 退货淘宝极速退款 卖家拒收怎么办 淘宝退货极速退款后卖家拒收怎么办 蘑菇街付款成功怎么申请退款怎么办 淘宝上拍错地址联系卖家不管怎么办 收到货想退款卖家不同意怎么办 小米小店复合通过qq群怎么办 买了火车票在订单上查不到怎么办 用支付宝付款扣款没成功怎么办 在京东买东西只收到空盒子怎么办 魅族移动数据是灰色的怎么办? 魅族手机账号密码忘记了怎么办视频 淘宝购物退货把单号写错了怎么办 天猫想退货商家不给退货地址怎么办 天天爱消除四星宠物等级已满怎么办 店不干了店里面的财神怎么办 微信显示登陆注册语言打不开怎么办 三星手机解锁以后突然不量怎么办 耐克、阿迪品牌鉴定买到假货怎么办 小米4c盒子不支持有线连接怎么办 一个手机号绑着两个小米账号怎么办 小米5s手机听筒声音小怎么办 淘宝上买手机买到翻新怎么办 小米6用久了很卡怎么办 淘宝商家发错误的退货地址怎么办 买苹果手机时查到了翻新机该怎么办 荣耀9青春版玩王者卡怎么办 红米4x手机声音突然成破音怎么办 红米pro玩王者荣耀卡怎么办 红米手机恢复出厂设置出错了怎么办 红米恢复出厂设置出错了怎么办 应聘工作上当收押金了该怎么办 红米1s密码忘了怎么办 红米1s刷机后开不了机怎么办 红米2a耗电超快怎么办 红米2a手机耗电快怎么办 红米4x触屏失灵怎么办 苹果恢复出厂设置后密码忘记怎么办 红米1s忘记密码锁屏了怎么办 红米3手机忘记解锁图案怎么办 小米5x手机录屏失败怎么办 红米4x手机wif信号不好怎么办